11using System . Text ;
22
3+ using Microsoft . Extensions . Primitives ;
4+
35using PhenX . EntityFrameworkCore . BulkInsert . Dialect ;
46using PhenX . EntityFrameworkCore . BulkInsert . Metadata ;
57using PhenX . EntityFrameworkCore . BulkInsert . Options ;
@@ -18,16 +20,10 @@ public override string BuildMoveDataSql<T>(
1820 TableMetadata target ,
1921 string source ,
2022 IReadOnlyList < PropertyMetadata > insertedProperties ,
21- IReadOnlyList < PropertyMetadata > properties ,
23+ IReadOnlyList < PropertyMetadata > returnedProperties ,
2224 BulkInsertOptions options ,
2325 OnConflictOptions ? onConflict = null )
2426 {
25- var insertedColumns = insertedProperties . Select ( x => x . QuotedColumName ) ;
26- var insertedColumnList = string . Join ( ", " , insertedColumns ) ;
27-
28- var returnedColumns = properties . Select ( p => $ "INSERTED.{ p . ColumnName } AS { p . ColumnName } ") ;
29- var columnList = string . Join ( ", " , returnedColumns ) ;
30-
3127 var q = new StringBuilder ( ) ;
3228
3329 if ( options . CopyGeneratedColumns )
@@ -36,49 +32,76 @@ public override string BuildMoveDataSql<T>(
3632 }
3733
3834 // Merge handling
39- if ( onConflict is OnConflictOptions < T > onConflictTyped && onConflictTyped . Match != null )
35+ if ( onConflict is OnConflictOptions < T > onConflictTyped )
4036 {
41- var matchColumns = GetColumns ( target , onConflictTyped . Match ) ;
42- var matchOn = string . Join ( " AND " ,
43- matchColumns . Select ( col => $ "TARGET.{ col } = SOURCE.{ col } ") ) ;
44-
45- var updateSet = onConflictTyped . Update != null
46- ? string . Join ( ", " , GetUpdates ( target , insertedProperties , onConflictTyped . Update ) )
47- : null ;
37+ IEnumerable < string > matchColumns ;
38+ if ( onConflictTyped . Match != null )
39+ {
40+ matchColumns = GetColumns ( target , onConflictTyped . Match ) ;
41+ }
42+ else if ( target . PrimaryKey . Count > 0 )
43+ {
44+ matchColumns = target . PrimaryKey . Select ( x => x . QuotedColumName ) ;
45+ }
46+ else
47+ {
48+ throw new InvalidOperationException ( "Table has no primary key that can be used for conflict detection." ) ;
49+ }
4850
4951 q . AppendLine ( $ "MERGE INTO { target . QuotedTableName } AS TARGET") ;
50- q . AppendLine (
51- $ "USING (SELECT { string . Join ( ", " , insertedColumns ) } FROM { source } ) AS SOURCE ({ insertedColumnList } )") ;
52- q . AppendLine ( $ "ON { matchOn } ") ;
5352
54- if ( updateSet != null )
53+ q . Append ( "USING (SELECT " ) ;
54+ q . AppendColumns ( insertedProperties ) ;
55+ q . Append ( $ " FROM { source } ) AS SOURCE (") ;
56+ q . AppendColumns ( insertedProperties ) ;
57+ q . AppendLine ( ")" ) ;
58+
59+ q . Append ( "ON " ) ;
60+ q . AppendJoin ( $ " AND ", matchColumns , ( b , col ) => b . Append ( $ "TARGET.{ col } = SOURCE.{ col } ") ) ;
61+ q . AppendLine ( ) ;
62+
63+ if ( onConflictTyped . Update != null )
5564 {
56- q . AppendLine ( $ "WHEN MATCHED THEN UPDATE SET { updateSet } ") ;
65+ q . AppendLine ( $ "WHEN MATCHED THEN UPDATE SET ") ;
66+ q . AppendJoin ( ", " , GetUpdates ( target , insertedProperties , onConflictTyped . Update ) ) ;
67+ q . AppendLine ( ) ;
5768 }
5869
59- q . AppendLine (
60- $ "WHEN NOT MATCHED THEN INSERT ({ insertedColumnList } ) VALUES ({ string . Join ( ", " , insertedColumns . Select ( c => $ "SOURCE.{ c } ") ) } )") ;
70+ q . Append ( $ "WHEN NOT MATCHED THEN INSERT (") ;
71+ q . AppendColumns ( insertedProperties ) ;
72+ q . AppendLine ( ")" ) ;
73+
74+ q . Append ( "VALUES (" ) ;
75+ q . AppendJoin ( ", " , insertedProperties , ( b , col ) => b . Append ( $ "SOURCE.{ col . QuotedColumName } ") ) ;
76+ q . AppendLine ( ")" ) ;
6177
62- if ( columnList . Length != 0 )
78+ if ( returnedProperties . Count != 0 )
6379 {
64- q . AppendLine ( $ "OUTPUT { columnList } ") ;
80+ q . Append ( "OUTPUT " ) ;
81+ q . AppendJoin ( $ ", ", returnedProperties , ( b , col ) => b . Append ( $ "INSERTED.{ col . QuotedColumName } AS { col . QuotedColumName } ") ) ;
82+ q . AppendLine ( ) ;
6583 }
6684 }
6785
6886 // No conflict handling
6987 else
7088 {
71- q . AppendLine ( $ "INSERT INTO { target . QuotedTableName } ({ insertedColumnList } )") ;
89+ q . Append ( $ "INSERT INTO { target . QuotedTableName } (") ;
90+ q . AppendColumns ( insertedProperties ) ;
91+ q . AppendLine ( ")" ) ;
7292
73- if ( columnList . Length != 0 )
93+ if ( returnedProperties . Count != 0 )
7494 {
75- q . AppendLine ( $ "OUTPUT { columnList } ") ;
95+ q . Append ( "OUTPUT " ) ;
96+ q . AppendJoin ( $ ", ", returnedProperties , ( b , col ) => b . Append ( $ "INSERTED.{ col . QuotedColumName } AS { col . QuotedColumName } ") ) ;
97+ q . AppendLine ( ) ;
7698 }
7799
78- q . AppendLine ( $ """
79- SELECT { insertedColumnList }
80- FROM { source }
81- """ ) ;
100+ q . Append ( "SELECT " ) ;
101+ q . AppendColumns ( insertedProperties ) ;
102+ q . AppendLine ( ) ;
103+ q . Append ( $ "FROM { source } ") ;
104+ q . AppendLine ( ) ;
82105 }
83106
84107 q . AppendLine ( ";" ) ;
@@ -88,7 +111,8 @@ public override string BuildMoveDataSql<T>(
88111 q . AppendLine ( $ "SET IDENTITY_INSERT { target . QuotedTableName } OFF;") ;
89112 }
90113
91- return q . ToString ( ) ;
114+ var x = q . ToString ( ) ;
115+ return x ;
92116 }
93117
94118 protected override string GetExcludedColumnName ( string columnName )
0 commit comments