@@ -14,20 +14,34 @@ internal class SqlServerDialectBuilder : SqlDialectBuilder
1414
1515 protected override bool SupportsMoveRows => false ;
1616
17+ public override string CreateTableCopySql ( string tempTableName , TableMetadata tableInfo , IReadOnlyList < PropertyMetadata > columns )
18+ {
19+ var q = new StringBuilder ( ) ;
20+ q . Append ( $ "CREATE TABLE { tempTableName } (") ;
21+
22+ foreach ( var column in columns )
23+ {
24+ q . Append ( $ "{ column . QuotedColumName } { column . StoreDefinition } ") ;
25+ if ( column != columns [ ^ 1 ] )
26+ {
27+ q . Append ( ',' ) ;
28+ }
29+ q . AppendLine ( ) ;
30+ }
31+
32+ q . AppendLine ( ")" ) ;
33+
34+ return q . ToString ( ) ;
35+ }
36+
1737 public override string BuildMoveDataSql < T > (
1838 TableMetadata target ,
1939 string source ,
2040 IReadOnlyList < PropertyMetadata > insertedProperties ,
21- IReadOnlyList < PropertyMetadata > properties ,
41+ IReadOnlyList < PropertyMetadata > returnedProperties ,
2242 BulkInsertOptions options ,
2343 OnConflictOptions ? onConflict = null )
2444 {
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-
3145 var q = new StringBuilder ( ) ;
3246
3347 if ( options . CopyGeneratedColumns )
@@ -36,49 +50,78 @@ public override string BuildMoveDataSql<T>(
3650 }
3751
3852 // Merge handling
39- if ( onConflict is OnConflictOptions < T > onConflictTyped && onConflictTyped . Match != null )
53+ if ( onConflict is OnConflictOptions < T > onConflictTyped )
4054 {
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 ;
55+ IEnumerable < string > matchColumns ;
56+ if ( onConflictTyped . Match != null )
57+ {
58+ matchColumns = GetColumns ( target , onConflictTyped . Match ) ;
59+ }
60+ else if ( target . PrimaryKey . Count > 0 )
61+ {
62+ matchColumns = target . PrimaryKey . Select ( x => x . QuotedColumName ) ;
63+ }
64+ else
65+ {
66+ throw new InvalidOperationException ( "Table has no primary key that can be used for conflict detection." ) ;
67+ }
4868
4969 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 } ") ;
5370
54- if ( updateSet != null )
71+ q . Append ( "USING (SELECT " ) ;
72+ q . AppendColumns ( insertedProperties ) ;
73+ q . Append ( $ " FROM { source } ) AS SOURCE (") ;
74+ q . AppendColumns ( insertedProperties ) ;
75+ q . AppendLine ( ")" ) ;
76+
77+ q . Append ( "ON " ) ;
78+ q . AppendJoin ( $ " AND ", matchColumns , ( b , col ) => b . Append ( $ "TARGET.{ col } = SOURCE.{ col } ") ) ;
79+ q . AppendLine ( ) ;
80+
81+ if ( onConflictTyped . Update != null )
5582 {
56- q . AppendLine ( $ "WHEN MATCHED THEN UPDATE SET { updateSet } ") ;
83+ var properties = target . GetProperties ( false ) ;
84+
85+ q . AppendLine ( $ "WHEN MATCHED THEN UPDATE SET ") ;
86+ q . AppendJoin ( ", " , GetUpdates ( target , properties , onConflictTyped . Update ) ) ;
87+ q . AppendLine ( ) ;
5788 }
5889
59- q . AppendLine (
60- $ "WHEN NOT MATCHED THEN INSERT ({ insertedColumnList } ) VALUES ({ string . Join ( ", " , insertedColumns . Select ( c => $ "SOURCE.{ c } ") ) } )") ;
90+ q . Append ( $ "WHEN NOT MATCHED THEN INSERT (") ;
91+ q . AppendColumns ( insertedProperties ) ;
92+ q . AppendLine ( ")" ) ;
93+
94+ q . Append ( "VALUES (" ) ;
95+ q . AppendJoin ( ", " , insertedProperties , ( b , col ) => b . Append ( $ "SOURCE.{ col . QuotedColumName } ") ) ;
96+ q . AppendLine ( ")" ) ;
6197
62- if ( columnList . Length != 0 )
98+ if ( returnedProperties . Count != 0 )
6399 {
64- q . AppendLine ( $ "OUTPUT { columnList } ") ;
100+ q . Append ( "OUTPUT " ) ;
101+ q . AppendJoin ( $ ", ", returnedProperties , ( b , col ) => b . Append ( $ "INSERTED.{ col . QuotedColumName } AS { col . QuotedColumName } ") ) ;
102+ q . AppendLine ( ) ;
65103 }
66104 }
67105
68106 // No conflict handling
69107 else
70108 {
71- q . AppendLine ( $ "INSERT INTO { target . QuotedTableName } ({ insertedColumnList } )") ;
109+ q . Append ( $ "INSERT INTO { target . QuotedTableName } (") ;
110+ q . AppendColumns ( insertedProperties ) ;
111+ q . AppendLine ( ")" ) ;
72112
73- if ( columnList . Length != 0 )
113+ if ( returnedProperties . Count != 0 )
74114 {
75- q . AppendLine ( $ "OUTPUT { columnList } ") ;
115+ q . Append ( "OUTPUT " ) ;
116+ q . AppendJoin ( $ ", ", returnedProperties , ( b , col ) => b . Append ( $ "INSERTED.{ col . QuotedColumName } AS { col . QuotedColumName } ") ) ;
117+ q . AppendLine ( ) ;
76118 }
77119
78- q . AppendLine ( $ """
79- SELECT { insertedColumnList }
80- FROM { source }
81- """ ) ;
120+ q . Append ( "SELECT " ) ;
121+ q . AppendColumns ( insertedProperties ) ;
122+ q . AppendLine ( ) ;
123+ q . Append ( $ "FROM { source } ") ;
124+ q . AppendLine ( ) ;
82125 }
83126
84127 q . AppendLine ( ";" ) ;
@@ -88,7 +131,8 @@ public override string BuildMoveDataSql<T>(
88131 q . AppendLine ( $ "SET IDENTITY_INSERT { target . QuotedTableName } OFF;") ;
89132 }
90133
91- return q . ToString ( ) ;
134+ var result = q . ToString ( ) ;
135+ return result ;
92136 }
93137
94138 protected override string GetExcludedColumnName ( string columnName )
0 commit comments