Skip to content

Commit 351e33d

Browse files
committed
Merge branch 'master' of https://github.com/dotnetcore/FreeSql
2 parents 1f6e16f + a6a9d02 commit 351e33d

File tree

11 files changed

+169
-22
lines changed

11 files changed

+169
-22
lines changed

FreeSql.DbContext/UnitOfWork/UnitOfWorkManager.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,31 @@ namespace FreeSql
1111
/// <summary>
1212
/// 工作单元管理器
1313
/// </summary>
14-
public class UnitOfWorkManager : IDisposable
14+
public interface IUnitOfWorkManager : IDisposable
15+
{
16+
IFreeSql Orm { get; }
17+
/// <summary>
18+
/// 当前的工作单元
19+
/// </summary>
20+
IUnitOfWork Current { get; }
21+
/// <summary>
22+
/// 将仓储的事务交给我管理
23+
/// </summary>
24+
/// <param name="repository"></param>
25+
void Binding(IBaseRepository repository);
26+
/// <summary>
27+
/// 创建工作单元
28+
/// </summary>
29+
/// <param name="propagation">事务传播方式</param>
30+
/// <param name="isolationLevel">事务隔离级别</param>
31+
/// <returns></returns>
32+
IUnitOfWork Begin(Propagation propagation = Propagation.Required, IsolationLevel? isolationLevel = null);
33+
}
34+
35+
/// <summary>
36+
/// 工作单元管理器
37+
/// </summary>
38+
public class UnitOfWorkManager : IUnitOfWorkManager
1539
{
1640
internal DbContextScopedFreeSql _ormScoped;
1741
internal IFreeSql OrmOriginal => _ormScoped?._originalFsql;

FreeSql.Tests/FreeSql.Tests/PostgreSQL/Curd/PostgreSQLInsertOrUpdateTest.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,37 @@ ON CONFLICT(""id"") DO UPDATE SET
9898
var lst = fsql.Select<tbiou02>().Where(a => new[] { 1, 2, 3, 4 }.Contains(a.id)).ToList();
9999
Assert.Equal(4, lst.Where(a => a.name == "00" + a.id).Count());
100100
}
101+
101102
class tbiou02
102103
{
103104
public int id { get; set; }
104105
public string name { get; set; }
105106
}
107+
108+
[Fact]
109+
public void InsertOrUpdate_TempPrimary()
110+
{
111+
fsql.Delete<tbiou_temp>().Where("1=1").ExecuteAffrows();
112+
var iou = fsql.InsertOrUpdate<tbiou_temp>().SetSource(new tbiou_temp { name = "01", description = "testval" }, m => new { m.name });
113+
var sql = iou.ToSql();
114+
Assert.Equal(@"INSERT INTO ""tbiou_temp""(""name"", ""description"") VALUES('01', 'testval')
115+
ON CONFLICT(""name"") DO UPDATE SET
116+
""description"" = EXCLUDED.""description""", sql);
117+
Assert.Equal(1, iou.ExecuteAffrows());
118+
119+
var iou2 = fsql.InsertOrUpdate<tbiou_temp>().SetSource(new tbiou_temp { name = "01", description = "testval2" }, m => new { m.name }).ExecuteAffrows();
120+
Assert.Equal(1, iou2);
121+
122+
}
123+
[Index("uix_tbiou_temp_name", "name", true)]
124+
class tbiou_temp
125+
{
126+
[Column(IsPrimary = true, IsIdentity = true)]
127+
public int id { get; set; }
128+
129+
public string name { get; set; }
130+
public string description { get; set; }
131+
}
106132
[Fact]
107133
public void InsertOrUpdate_OnePrimaryAndIdentity()
108134
{

FreeSql/Extensions/FreeSqlGlobalExtensions.cs

Lines changed: 91 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -420,21 +420,102 @@ static TReturn LocalWithIndex<TReturn>(TReturn query, string indexName, Dictiona
420420
case DataType.SqlServer:
421421
case DataType.OdbcSqlServer:
422422
case DataType.CustomSqlServer:
423+
{
424+
var oldalias = selectProvider._aliasRule;
425+
selectProvider._aliasRule = (type, old) =>
426+
{
427+
if (oldalias != null) old = oldalias(type, old);
428+
if (string.IsNullOrWhiteSpace(indexName) == false && type == selectProvider._tables[0].Table.Type) return LocalAppendWithString(old, $"index={indexName}");
429+
if (rule == null) return old;
430+
return rule.TryGetValue(type, out var tryidxName) && string.IsNullOrWhiteSpace(tryidxName) == false ? LocalAppendWithString(old, $"index={tryidxName}") : old;
431+
};
432+
}
433+
break;
434+
case DataType.MySql:
435+
case DataType.OdbcMySql:
436+
case DataType.CustomMySql:
437+
{
438+
var oldalias = selectProvider._aliasRule;
439+
selectProvider._aliasRule = (type, old) =>
440+
{
441+
if (oldalias != null) old = oldalias(type, old);
442+
if (string.IsNullOrWhiteSpace(indexName) == false && type == selectProvider._tables[0].Table.Type) return LocalAppendMySqlIndex(old, indexName);
443+
if (rule == null) return old;
444+
return rule.TryGetValue(type, out var tryidxName) && string.IsNullOrWhiteSpace(tryidxName) == false ? LocalAppendMySqlIndex(old, indexName) : old;
445+
};
446+
}
447+
break;
448+
case DataType.Oracle:
449+
case DataType.OdbcOracle:
450+
case DataType.CustomOracle:
451+
{
452+
var hintParts = new List<string>();
453+
if (!string.IsNullOrEmpty(indexName) && !string.IsNullOrEmpty(selectProvider._tables[0].Alias))
454+
{
455+
string alias = selectProvider._tables[0].Alias;
456+
hintParts.Add($"INDEX({alias} {indexName})");
457+
}
458+
if (rule != null && rule.Count > 0)
459+
{
460+
var tablesMap = selectProvider._tables
461+
.Skip(1)
462+
.Where(t => !string.IsNullOrEmpty(t.Alias) && t.Table?.Type != null)
463+
.ToDictionary(t => t.Table.Type, t => t);
464+
foreach (var indexRule in rule)
465+
{
466+
if (tablesMap.TryGetValue(indexRule.Key, out var tableInfo))
467+
{
468+
string otherIndexName = indexRule.Value;
469+
if (!string.IsNullOrEmpty(otherIndexName))
470+
hintParts.Add($"INDEX({tableInfo.Alias} {otherIndexName})");
471+
}
472+
}
473+
}
474+
if (hintParts.Count > 0)
475+
{
476+
string finalHint = $"/*+ {string.Join(" ", hintParts)} */";
477+
var _select = selectProvider._select;
478+
int selectKeywordIndex = _select.IndexOf("SELECT ", StringComparison.OrdinalIgnoreCase);
479+
if (selectKeywordIndex != -1)
480+
{
481+
int insertionPoint = selectKeywordIndex + "SELECT ".Length;
482+
selectProvider._select = _select.Insert(insertionPoint, $"{finalHint} ");
483+
}
484+
}
485+
}
486+
break;
487+
case DataType.Sqlite:
488+
{
489+
var oldalias = selectProvider._aliasRule;
490+
selectProvider._aliasRule = (type, old) =>
491+
{
492+
if (oldalias != null) old = oldalias(type, old);
493+
if (string.IsNullOrWhiteSpace(indexName) == false && type == selectProvider._tables[0].Table.Type) return LocalAppendSqliteIndex(old, indexName);
494+
if (rule == null) return old;
495+
return rule.TryGetValue(type, out var tryidxName) && string.IsNullOrWhiteSpace(tryidxName) == false ? LocalAppendSqliteIndex(old, indexName) : old;
496+
};
497+
}
423498
break;
424-
default:
425-
return query;
426499
}
427-
var oldalias = selectProvider._aliasRule;
428-
selectProvider._aliasRule = (type, old) =>
429-
{
430-
if (oldalias != null) old = oldalias(type, old);
431-
if (string.IsNullOrWhiteSpace(indexName) == false && type == selectProvider._tables[0].Table.Type) return LocalAppendWithString(old, $"index={indexName}");
432-
if (rule == null) return old;
433-
return rule.TryGetValue(type, out var tryidxName) && string.IsNullOrWhiteSpace(tryidxName) == false ? LocalAppendWithString(old, $"index={tryidxName}") : old;
434-
};
500+
435501
return query;
436502
}
437503
static string LocalAppendWithString(string old, string str) => old?.Contains(" With(") == true ? old.Replace(" With(", $" With({str}, ") : $"{old} With({str})";
504+
static string LocalAppendMySqlIndex(string old, string indexName)
505+
{
506+
if (string.IsNullOrEmpty(old)) return $"FORCE INDEX({indexName})";
507+
int forceIndexPosition = old.IndexOf("FORCE INDEX(", StringComparison.OrdinalIgnoreCase);
508+
if (forceIndexPosition == -1) return $"{old} FORCE INDEX({indexName})";
509+
int closingParenPosition = old.IndexOf(')', forceIndexPosition);
510+
if (closingParenPosition != -1) return old.Insert(closingParenPosition, $",{indexName}");
511+
return old;
512+
}
513+
static string LocalAppendSqliteIndex(string old, string indexName)
514+
{
515+
if (string.IsNullOrEmpty(old)) return $"INDEXED BY {indexName}";
516+
if (old.IndexOf("INDEXED BY", StringComparison.OrdinalIgnoreCase) != -1) return old;
517+
return $"{old} INDEXED BY {indexName}";
518+
}
438519

439520
/// <summary>
440521
/// 设置全局 SqlServer: with(nolock)<para></para>

Providers/FreeSql.Provider.ClickHouse/Curd/ClickHouseInsert.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,14 +185,21 @@ async protected override Task<int> RawExecuteAffrowsAsync(CancellationToken canc
185185
before = new Aop.CurdBeforeEventArgs(_table.Type, _table, Aop.CurdType.Insert, null, _params);
186186
_orm.Aop.CurdBeforeHandler?.Invoke(this, before);
187187
var data = ToDataTable();
188+
var columns = new string[_table.ColumnsByPosition.Length];
189+
for (var i = 0; i < columns.Length; i++)
190+
{
191+
columns[i] = _table.ColumnsByPosition[i].CsName;
192+
}
188193
using (var conn = await _orm.Ado.MasterPool.GetAsync())
189194
{
190195
using (var bulkCopyInterface = new ClickHouseBulkCopy(conn.Value as ClickHouseConnection)
191196
{
192197
DestinationTableName = data.TableName,
193-
BatchSize = _source.Count
198+
BatchSize = _source.Count,
199+
ColumnNames = columns,
194200
})
195201
{
202+
await bulkCopyInterface.InitAsync();
196203
await bulkCopyInterface.WriteToServerAsync(data, default);
197204
}
198205
}
@@ -201,7 +208,7 @@ async protected override Task<int> RawExecuteAffrowsAsync(CancellationToken canc
201208
catch (Exception ex)
202209
{
203210
exception = ex;
204-
throw ex;
211+
throw;
205212
}
206213
finally
207214
{

Providers/FreeSql.Provider.Custom/PostgreSQL/Curd/CustomPostgreSQLInsertOrUpdate.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ string getInsertSql(List<T1> data, bool flagInsert, bool noneParameter)
5656
if (IdentityColumn != null && flagInsert) sql = insert.ToSql();
5757
else
5858
{
59-
var ocdu = new CustomPostgreSQLOnConflictDoUpdate<T1>(insert.InsertIdentity());
59+
var ocdu = new CustomPostgreSQLOnConflictDoUpdate<T1>(_tempPrimarys?.Length > 0 ? insert : insert.InsertIdentity());
6060
ocdu._tempPrimarys = _tempPrimarys;
6161
var cols = _table.Columns.Values.Where(a => _updateSetDict.ContainsKey(a.Attribute.Name) ||
6262
_tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && a.Attribute.IsIdentity == false && _updateIgnore.ContainsKey(a.Attribute.Name) == false);

Providers/FreeSql.Provider.Duckdb/FreeSql.Provider.Duckdb.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
</ItemGroup>
2929

3030
<ItemGroup>
31-
<PackageReference Include="DuckDB.NET.Data.Full" Version="1.2.1" />
31+
<PackageReference Include="DuckDB.NET.Data.Full" Version="1.4.1" />
3232
</ItemGroup>
3333

3434
<ItemGroup>

Providers/FreeSql.Provider.KingbaseES/Curd/KingbaseESInsertOrUpdate.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ string getInsertSql(List<T1> data, bool flagInsert, bool noneParameter)
5656
if (IdentityColumn != null && flagInsert) sql = insert.ToSql();
5757
else
5858
{
59-
var ocdu = new KingbaseESOnConflictDoUpdate<T1>(insert.InsertIdentity());
59+
var ocdu = new KingbaseESOnConflictDoUpdate<T1>(_tempPrimarys?.Length > 0 ? insert : insert.InsertIdentity());
6060
ocdu._tempPrimarys = _tempPrimarys;
6161
var cols = _table.Columns.Values.Where(a => _updateSetDict.ContainsKey(a.Attribute.Name) ||
6262
_tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && a.Attribute.IsIdentity == false && _updateIgnore.ContainsKey(a.Attribute.Name) == false);

Providers/FreeSql.Provider.KingbaseES/KingbaseESCodeFirst.cs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,17 @@ public void InitIsSysV8R3()
149149
protected override string GetComparisonDDLStatements(params TypeSchemaAndName[] objects)
150150
{
151151
InitIsSysV8R3();
152+
var builder = new System.Data.Common.DbConnectionStringBuilder
153+
{
154+
ConnectionString = _orm.Ado.ConnectionString
155+
};
156+
var searchPath = builder.ContainsKey("SearchPath") ? builder["SearchPath"].ToString() : "PUBLIC"; //读取链接字符串中的SearchPath 来确定架构模式
157+
if (searchPath.Contains(','))
158+
{
159+
searchPath = searchPath.Split(',')[0];
160+
}
152161
var pg_ = _isSysV8R3 == true ? "sys_" : "pg_";
153-
var public_ = _isSysV8R3 == true ? "PUBLIC" : "public";
162+
var public_ = _isSysV8R3 == true ? searchPath.ToUpper() : searchPath;
154163
var sb = new StringBuilder();
155164
var seqcols = new List<NativeTuple<ColumnInfo, string[], bool>>(); //序列
156165

@@ -182,11 +191,11 @@ protected override string GetComparisonDDLStatements(params TypeSchemaAndName[]
182191

183192
var sbalter = new StringBuilder();
184193
var istmpatler = false; //创建临时表,导入数据,删除旧表,修改
185-
if (_orm.Ado.ExecuteScalar(CommandType.Text, string.Format($" select 1 from {pg_}tables a inner join {pg_}namespace b on b.nspname = a.schemaname where b.nspname || '.' || a.tablename = '{{0}}.{{1}}'", tbname)) == null)
194+
if (_orm.Ado.ExecuteScalar(CommandType.Text, string.Format($" select 1 from {pg_}tables a inner join {pg_}namespace b on b.nspname = a.schemaname where b.nspname ='{{0}}' && a.tablename = '{{1}}'", tbname)) == null)//原判断V9版本存在问题
186195
{ //表不存在
187196
if (tboldname != null)
188197
{
189-
if (_orm.Ado.ExecuteScalar(CommandType.Text, string.Format($" select 1 from {pg_}tables a inner join {pg_}namespace b on b.nspname = a.schemaname where b.nspname || '.' || a.tablename = '{{0}}.{{1}}'", tboldname)) == null)
198+
if (_orm.Ado.ExecuteScalar(CommandType.Text, string.Format($" select 1 from {pg_}tables a inner join {pg_}namespace b on b.nspname = a.schemaname where b.nspname ='{{0}}' && a.tablename = '{{1}}'", tboldname)) == null)
190199
//旧表不存在
191200
tboldname = null;
192201
}
@@ -388,7 +397,7 @@ d.description as comment
388397
inner join {pg_}namespace b on b.oid = a.relnamespace
389398
left join {pg_}description d on d.objoid = a.oid and objsubid = 0
390399
where upper(b.nspname) not in ('SYS_CATALOG', 'INFORMATION_SCHEMA', 'TOPOLOGY', 'SYSAUDIT', 'SYSLOGICAL', 'SYS_TEMP_1', 'SYS_TOAST', 'SYS_TOAST_TEMP_1', 'XLOG_RECORD_READ') and a.relkind in ('r') and b.nspname = {{0}} and a.relname = {{1}}
391-
and upper(b.nspname || '.' || a.relname) not in ('PUBLIC.GEOGRAPHY_COLUMNS','PUBLIC.GEOMETRY_COLUMNS','PUBLIC.RASTER_COLUMNS','PUBLIC.RASTER_OVERVIEWS')", tbname[0], tbname[1])));
400+
and upper(text(b.nspname || '.' || a.relname)) not in ('PUBLIC.GEOGRAPHY_COLUMNS','PUBLIC.GEOMETRY_COLUMNS','PUBLIC.RASTER_COLUMNS','PUBLIC.RASTER_OVERVIEWS')", tbname[0], tbname[1])));//解决报错 function upper(boolean) is not unique 错误的问题
392401
if (dbcomment != (tb.Comment ?? ""))
393402
sbalter.Append("COMMENT ON TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tb.Comment)).Append(";\r\n");
394403

128 KB
Binary file not shown.

Providers/FreeSql.Provider.Odbc/PostgreSQL/Curd/OdbcPostgreSQLInsertOrUpdate.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ string getInsertSql(List<T1> data, bool flagInsert, bool noneParameter)
5656
if (IdentityColumn != null && flagInsert) sql = insert.ToSql();
5757
else
5858
{
59-
var ocdu = new OdbcPostgreSQLOnConflictDoUpdate<T1>(insert.InsertIdentity());
59+
var ocdu = new OdbcPostgreSQLOnConflictDoUpdate<T1>(_tempPrimarys?.Length > 0 ? insert : insert.InsertIdentity());
6060
ocdu._tempPrimarys = _tempPrimarys;
6161
var cols = _table.Columns.Values.Where(a => _updateSetDict.ContainsKey(a.Attribute.Name) ||
6262
_tempPrimarys.Contains(a) == false && a.Attribute.CanUpdate == true && a.Attribute.IsIdentity == false && _updateIgnore.ContainsKey(a.Attribute.Name) == false);

0 commit comments

Comments
 (0)