From 52fbe5ed86c237ab6574c0497d99b34908e4e0da Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Fri, 10 Apr 2020 19:54:43 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E4=BC=98=E5=8C=96=20DbContext/Repository?= =?UTF-8?q?=20Orm=20=E5=B1=9E=E6=80=A7=E8=BF=9B=E8=A1=8C=20CURD=20?= =?UTF-8?q?=E4=B8=8E=E8=87=AA=E8=BA=AB=E4=BA=8B=E5=8A=A1=E7=9B=B8=E5=90=8C?= =?UTF-8?q?=E3=80=90=E6=96=B0=E7=AA=81=E7=A0=B4=E3=80=91=EF=BC=9B#270?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FreeSql.DbContext/DbContext/DbContext.cs | 24 +- .../DbContext/DbContextScopedFreeSql.cs | 74 + FreeSql.DbContext/DbContext/FreeContext.cs | 2 +- FreeSql.DbContext/DbSet/DbSet.cs | 70 +- FreeSql.DbContext/DbSet/DbSetAsync.cs | 56 +- FreeSql.DbContext/DbSet/DbSetSync.cs | 60 +- .../Extensions/DependencyInjection.cs | 6 +- FreeSql.DbContext/FreeSql.DbContext.xml | 12 - .../ContextSet/RepositoryDbContext.cs | 4 +- .../Repository/ContextSet/RepositoryDbSet.cs | 4 +- .../Repository/Repository/BaseRepository.cs | 13 +- .../Repository/Repository/IBaseRepository.cs | 5 - .../RepositoryTests.cs | 11 + .../FreeSql.Tests.DbContext/UnitTest1.cs | 11 +- FreeSql/FreeSql.xml | 7377 ++++++++--------- .../Internal/CommonProvider/InsertProvider.cs | 2 +- .../Internal/CommonProvider/UpdateProvider.cs | 2 +- 17 files changed, 3884 insertions(+), 3849 deletions(-) create mode 100644 FreeSql.DbContext/DbContext/DbContextScopedFreeSql.cs diff --git a/FreeSql.DbContext/DbContext/DbContext.cs b/FreeSql.DbContext/DbContext/DbContext.cs index c4ac6da4..49f044f1 100644 --- a/FreeSql.DbContext/DbContext/DbContext.cs +++ b/FreeSql.DbContext/DbContext/DbContext.cs @@ -10,13 +10,9 @@ namespace FreeSql { public abstract partial class DbContext : IDisposable { - internal IFreeSql _ormPriv; - - /// - /// 注意:IFreeSql 属于顶级对象,事务无法自动传递。 - /// 手工传递事务:ISelect/IInsert/IDelete/IUpdate 可以使用 WithTransaction(uow.GetOrBeginTransaction()) - /// - public IFreeSql Orm => _ormPriv ?? throw new ArgumentNullException("请在 OnConfiguring 或 AddFreeDbContext 中配置 UseFreeSql"); + internal DbContextScopedFreeSql _ormScoped; + internal IFreeSql OrmOriginal => _ormScoped?._originalFsql ?? throw new ArgumentNullException("请在 OnConfiguring 或 AddFreeDbContext 中配置 UseFreeSql"); + public IFreeSql Orm => _ormScoped ?? throw new ArgumentNullException("请在 OnConfiguring 或 AddFreeDbContext 中配置 UseFreeSql"); #region Property UnitOfWork internal bool _isUseUnitOfWork = true; //是否创建工作单元事务 @@ -28,7 +24,7 @@ namespace FreeSql { if (_uowPriv != null) return _uowPriv; if (_isUseUnitOfWork == false) return null; - return _uowPriv = new UnitOfWork(Orm); + return _uowPriv = new UnitOfWork(OrmOriginal); } } #endregion @@ -43,7 +39,7 @@ namespace FreeSql if (_optionsPriv == null) { _optionsPriv = new DbContextOptions(); - if (FreeSqlDbContextExtensions._dicSetDbContextOptions.TryGetValue(Orm.Ado.Identifier, out var opt)) + if (FreeSqlDbContextExtensions._dicSetDbContextOptions.TryGetValue(OrmOriginal.Ado.Identifier, out var opt)) { _optionsPriv.EnableAddOrUpdateNavigateList = opt.EnableAddOrUpdateNavigateList; _optionsPriv.OnEntityChange = opt.OnEntityChange; @@ -63,17 +59,17 @@ namespace FreeSql protected DbContext() : this(null, null) { } protected DbContext(IFreeSql fsql, DbContextOptions options) { - _ormPriv = fsql; + _ormScoped = DbContextScopedFreeSql.Create(fsql, () => this, () => UnitOfWork); _optionsPriv = options; - if (_ormPriv == null) + if (_ormScoped == null) { var builder = new DbContextOptionsBuilder(); OnConfiguring(builder); - _ormPriv = builder._fsql; + _ormScoped = DbContextScopedFreeSql.Create(builder._fsql, () => this, () => UnitOfWork); _optionsPriv = builder._options; } - if (_ormPriv != null) InitPropSets(); + if (_ormScoped != null) InitPropSets(); } protected virtual void OnConfiguring(DbContextOptionsBuilder builder) { } @@ -113,7 +109,7 @@ namespace FreeSql #region DbSet 快速代理 void CheckEntityTypeOrThrow(Type entityType) { - if (Orm.CodeFirst.GetTableByEntity(entityType) == null) + if (OrmOriginal.CodeFirst.GetTableByEntity(entityType) == null) throw new ArgumentException($"参数 data 类型错误 {entityType.FullName} "); } /// diff --git a/FreeSql.DbContext/DbContext/DbContextScopedFreeSql.cs b/FreeSql.DbContext/DbContext/DbContextScopedFreeSql.cs new file mode 100644 index 00000000..b188b937 --- /dev/null +++ b/FreeSql.DbContext/DbContext/DbContextScopedFreeSql.cs @@ -0,0 +1,74 @@ +using FreeSql; +using FreeSql.Internal; +using System; +using System.Collections.Generic; +using System.Data; +using System.Text; + +namespace FreeSql +{ + class DbContextScopedFreeSql : IFreeSql + { + public IFreeSql _originalFsql; + Func _resolveDbContext; + Func _resolveUnitOfWork; + DbContextScopedFreeSql() { } + + public static DbContextScopedFreeSql Create(IFreeSql fsql, Func resolveDbContext, Func resolveUnitOfWork) + { + if (fsql == null) return null; + var scopedfsql = fsql as DbContextScopedFreeSql; + if (scopedfsql == null) return new DbContextScopedFreeSql { _originalFsql = fsql, _resolveDbContext = resolveDbContext, _resolveUnitOfWork = resolveUnitOfWork }; + return Create(scopedfsql._originalFsql, resolveDbContext, resolveUnitOfWork); + } + + public IAdo Ado => _originalFsql.Ado; + public IAop Aop => _originalFsql.Aop; + public ICodeFirst CodeFirst => _originalFsql.CodeFirst; + public IDbFirst DbFirst => _originalFsql.DbFirst; + public GlobalFilter GlobalFilter => _originalFsql.GlobalFilter; + public void Dispose() { } + + public void Transaction(Action handler) => _originalFsql.Transaction(handler); + public void Transaction(TimeSpan timeout, Action handler) => _originalFsql.Transaction(timeout, handler); + public void Transaction(IsolationLevel isolationLevel, TimeSpan timeout, Action handler) => _originalFsql.Transaction(isolationLevel, timeout, handler); + + public ISelect Select() where T1 : class + { + _resolveDbContext()?.ExecCommand(); + return _originalFsql.Select().WithTransaction(_resolveUnitOfWork()?.GetOrBeginTransaction(false)); + } + public ISelect Select(object dywhere) where T1 : class => Select().WhereDynamic(dywhere); + + public IDelete Delete() where T1 : class + { + _resolveDbContext()?.ExecCommand(); + return _originalFsql.Delete().WithTransaction(_resolveUnitOfWork()?.GetOrBeginTransaction()); + } + public IDelete Delete(object dywhere) where T1 : class => Delete().WhereDynamic(dywhere); + + public IUpdate Update() where T1 : class + { + var db = _resolveDbContext(); + db?.ExecCommand(); + var update = _originalFsql.Update().WithTransaction(_resolveUnitOfWork()?.GetOrBeginTransaction()); + if (db?.Options.NoneParameter != null) update.NoneParameter(db.Options.NoneParameter.Value); + return update; + } + public IUpdate Update(object dywhere) where T1 : class => Update().WhereDynamic(dywhere); + + public IInsert Insert() where T1 : class + { + var db = _resolveDbContext(); + db?.ExecCommand(); + var insert = _originalFsql.Insert().WithTransaction(_resolveUnitOfWork()?.GetOrBeginTransaction()); + if (db?.Options.NoneParameter != null) insert.NoneParameter(db.Options.NoneParameter.Value); + return insert; + } + public IInsert Insert(T1 source) where T1 : class => Insert().AppendData(source); + public IInsert Insert(T1[] source) where T1 : class => Insert().AppendData(source); + public IInsert Insert(List source) where T1 : class => Insert().AppendData(source); + public IInsert Insert(IEnumerable source) where T1 : class => Insert().AppendData(source); + + } +} diff --git a/FreeSql.DbContext/DbContext/FreeContext.cs b/FreeSql.DbContext/DbContext/FreeContext.cs index 62fbe1c7..ab7a262f 100644 --- a/FreeSql.DbContext/DbContext/FreeContext.cs +++ b/FreeSql.DbContext/DbContext/FreeContext.cs @@ -7,7 +7,7 @@ namespace FreeSql public FreeContext(IFreeSql orm) { - _ormPriv = orm; + _ormScoped = DbContextScopedFreeSql.Create(orm, () => this, () => UnitOfWork); } } } diff --git a/FreeSql.DbContext/DbSet/DbSet.cs b/FreeSql.DbContext/DbSet/DbSet.cs index 9dfe6aa2..32efd9dd 100644 --- a/FreeSql.DbContext/DbSet/DbSet.cs +++ b/FreeSql.DbContext/DbSet/DbSet.cs @@ -33,7 +33,7 @@ namespace FreeSql protected virtual ISelect OrmSelect(object dywhere) { DbContextExecCommand(); //查询前先提交,否则会出脏读 - return _db.Orm.Select().AsType(_entityType).WithTransaction(_uow?.GetOrBeginTransaction(false)).TrackToList(TrackToList).WhereDynamic(dywhere); + return _db.OrmOriginal.Select().AsType(_entityType).WithTransaction(_uow?.GetOrBeginTransaction(false)).TrackToList(TrackToList).WhereDynamic(dywhere); } ~DbSet() => this.Dispose(); @@ -54,7 +54,7 @@ namespace FreeSql protected virtual IInsert OrmInsert() { - var insert = _db.Orm.Insert().AsType(_entityType).WithTransaction(_uow?.GetOrBeginTransaction()); + var insert = _db.OrmOriginal.Insert().AsType(_entityType).WithTransaction(_uow?.GetOrBeginTransaction()); if (_db.Options.NoneParameter != null) insert.NoneParameter(_db.Options.NoneParameter.Value); return insert; } @@ -63,11 +63,11 @@ namespace FreeSql protected virtual IUpdate OrmUpdate(IEnumerable entitys) { - var update = _db.Orm.Update().AsType(_entityType).WithTransaction(_uow?.GetOrBeginTransaction()); + var update = _db.OrmOriginal.Update().AsType(_entityType).WithTransaction(_uow?.GetOrBeginTransaction()); if (_db.Options.NoneParameter != null) update.NoneParameter(_db.Options.NoneParameter.Value); return update.SetSource(entitys); } - protected virtual IDelete OrmDelete(object dywhere) => _db.Orm.Delete().AsType(_entityType).WithTransaction(_uow?.GetOrBeginTransaction()).WhereDynamic(dywhere); + protected virtual IDelete OrmDelete(object dywhere) => _db.OrmOriginal.Delete().AsType(_entityType).WithTransaction(_uow?.GetOrBeginTransaction()).WhereDynamic(dywhere); internal void EnqueueToDbContext(DbContext.EntityChangeType changeType, EntityState state) => _db.EnqueueAction(changeType, this, typeof(EntityState), _entityType, state); @@ -89,7 +89,7 @@ namespace FreeSql var itemType = item.GetType(); if (itemType == typeof(object)) return; if (itemType.FullName.Contains("FreeSqlLazyEntity__")) itemType = itemType.BaseType; - if (_db.Orm.CodeFirst.GetTableByEntity(itemType)?.Primarys.Any() != true) return; + if (_db.OrmOriginal.CodeFirst.GetTableByEntity(itemType)?.Primarys.Any() != true) return; var dbset = _db.Set(itemType); dbset?.GetType().GetMethod("TrackToList", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(dbset, new object[] { list }); return; @@ -99,11 +99,11 @@ namespace FreeSql if (_table?.Primarys.Any() != true) return; foreach (var item in ls) { - var key = _db.Orm.GetEntityKeyString(_entityType, item, false); + var key = _db.OrmOriginal.GetEntityKeyString(_entityType, item, false); if (key == null) continue; _states.AddOrUpdate(key, k => CreateEntityState(item), (k, ov) => { - _db.Orm.MapEntityValue(_entityType, item, ov.Value); + _db.OrmOriginal.MapEntityValue(_entityType, item, ov.Value); ov.Time = DateTime.Now; return ov; }); @@ -117,7 +117,7 @@ namespace FreeSql protected ConcurrentDictionary _states = new ConcurrentDictionary(); internal ConcurrentDictionary _statesInternal => _states; TableInfo _tablePriv; - protected TableInfo _table => _tablePriv ?? (_tablePriv = _db.Orm.CodeFirst.GetTableByEntity(_entityType)); + protected TableInfo _table => _tablePriv ?? (_tablePriv = _db.OrmOriginal.CodeFirst.GetTableByEntity(_entityType)); ColumnInfo[] _tableIdentitysPriv, _tableServerTimesPriv; protected ColumnInfo[] _tableIdentitys => _tableIdentitysPriv ?? (_tableIdentitysPriv = _table.Primarys.Where(a => a.Attribute.IsIdentity).ToArray()); protected ColumnInfo[] _tableServerTimes => _tableServerTimesPriv ?? (_tableServerTimesPriv = _table.Primarys.Where(a => a.Attribute.ServerTime != DateTimeKind.Unspecified).ToArray()); @@ -133,7 +133,7 @@ namespace FreeSql { if (entityType == typeof(object)) throw new Exception("ISelect.AsType 参数不支持指定为 object"); if (entityType == _entityType) return this; - var newtb = _db.Orm.CodeFirst.GetTableByEntity(entityType); + var newtb = _db.OrmOriginal.CodeFirst.GetTableByEntity(entityType); _entityType = entityType; _tablePriv = newtb ?? throw new Exception("DbSet.AsType 参数错误,请传入正确的实体类型"); _tableIdentitysPriv = null; @@ -179,15 +179,15 @@ namespace FreeSql public void AttachRange(IEnumerable data) { if (data == null || data.Any() == false) return; - if (_table.Primarys.Any() == false) throw new Exception($"不可附加,实体没有主键:{_db.Orm.GetEntityString(_entityType, data.First())}"); + if (_table.Primarys.Any() == false) throw new Exception($"不可附加,实体没有主键:{_db.OrmOriginal.GetEntityString(_entityType, data.First())}"); foreach (var item in data) { - var key = _db.Orm.GetEntityKeyString(_entityType, item, false); - if (string.IsNullOrEmpty(key)) throw new Exception($"不可附加,未设置主键的值:{_db.Orm.GetEntityString(_entityType, item)}"); + var key = _db.OrmOriginal.GetEntityKeyString(_entityType, item, false); + if (string.IsNullOrEmpty(key)) throw new Exception($"不可附加,未设置主键的值:{_db.OrmOriginal.GetEntityString(_entityType, item)}"); _states.AddOrUpdate(key, k => CreateEntityState(item), (k, ov) => { - _db.Orm.MapEntityValue(_entityType, item, ov.Value); + _db.OrmOriginal.MapEntityValue(_entityType, item, ov.Value); ov.Time = DateTime.Now; return ov; }); @@ -201,10 +201,10 @@ namespace FreeSql { if (data == null) return this; var pkitem = (TEntity)Activator.CreateInstance(_entityType); - foreach (var pk in _db.Orm.CodeFirst.GetTableByEntity(_entityType).Primarys) + foreach (var pk in _db.OrmOriginal.CodeFirst.GetTableByEntity(_entityType).Primarys) { - var colVal = _db.Orm.GetEntityValueWithPropertyName(_entityType, data, pk.CsName); - _db.Orm.SetEntityValueWithPropertyName(_entityType, pkitem, pk.CsName, colVal); + var colVal = _db.OrmOriginal.GetEntityValueWithPropertyName(_entityType, data, pk.CsName); + _db.OrmOriginal.SetEntityValueWithPropertyName(_entityType, pkitem, pk.CsName, colVal); } this.Attach(pkitem); return this; @@ -222,15 +222,15 @@ namespace FreeSql EntityState CreateEntityState(TEntity data) { if (data == null) throw new ArgumentNullException(nameof(data)); - var key = _db.Orm.GetEntityKeyString(_entityType, data, false); + var key = _db.OrmOriginal.GetEntityKeyString(_entityType, data, false); var state = new EntityState((TEntity)Activator.CreateInstance(_entityType), key); - _db.Orm.MapEntityValue(_entityType, data, state.Value); + _db.OrmOriginal.MapEntityValue(_entityType, data, state.Value); return state; } bool? ExistsInStates(TEntity data) { if (data == null) throw new ArgumentNullException(nameof(data)); - var key = _db.Orm.GetEntityKeyString(_entityType, data, false); + var key = _db.OrmOriginal.GetEntityKeyString(_entityType, data, false); if (string.IsNullOrEmpty(key)) return null; return _states.ContainsKey(key); } @@ -255,14 +255,14 @@ namespace FreeSql } if (_table.Primarys.Any() == false) { - if (isThrow) throw new Exception($"不可添加,实体没有主键:{_db.Orm.GetEntityString(_entityType, data)}"); + if (isThrow) throw new Exception($"不可添加,实体没有主键:{_db.OrmOriginal.GetEntityString(_entityType, data)}"); return false; } - FreeSql.Internal.CommonProvider.InsertProvider.AuditDataValue(this, data, _db.Orm, _table, null); - var key = _db.Orm.GetEntityKeyString(_entityType, data, true); + FreeSql.Internal.CommonProvider.InsertProvider.AuditDataValue(this, data, _db.OrmOriginal, _table, null); + var key = _db.OrmOriginal.GetEntityKeyString(_entityType, data, true); if (string.IsNullOrEmpty(key)) { - switch (_db.Orm.Ado.DataType) + switch (_db.OrmOriginal.Ado.DataType) { case DataType.SqlServer: case DataType.OdbcSqlServer: @@ -272,7 +272,7 @@ namespace FreeSql default: if (_tableIdentitys.Length == 1 && _table.Primarys.Length == 1) return true; - if (isThrow) throw new Exception($"不可添加,未设置主键的值:{_db.Orm.GetEntityString(_entityType, data)}"); + if (isThrow) throw new Exception($"不可添加,未设置主键的值:{_db.OrmOriginal.GetEntityString(_entityType, data)}"); return false; } } @@ -280,13 +280,13 @@ namespace FreeSql { if (_states.ContainsKey(key)) { - if (isThrow) throw new Exception($"不可添加,已存在于状态管理:{_db.Orm.GetEntityString(_entityType, data)}"); + if (isThrow) throw new Exception($"不可添加,已存在于状态管理:{_db.OrmOriginal.GetEntityString(_entityType, data)}"); return false; } - var idval = _db.Orm.GetEntityIdentityValueWithPrimary(_entityType, data); + var idval = _db.OrmOriginal.GetEntityIdentityValueWithPrimary(_entityType, data); if (idval > 0) { - if (isThrow) throw new Exception($"不可添加,自增属性有值:{_db.Orm.GetEntityString(_entityType, data)}"); + if (isThrow) throw new Exception($"不可添加,自增属性有值:{_db.OrmOriginal.GetEntityString(_entityType, data)}"); return false; } } @@ -313,19 +313,19 @@ namespace FreeSql } if (_table.Primarys.Any() == false) { - if (isThrow) throw new Exception($"不可更新,实体没有主键:{_db.Orm.GetEntityString(_entityType, data)}"); + if (isThrow) throw new Exception($"不可更新,实体没有主键:{_db.OrmOriginal.GetEntityString(_entityType, data)}"); return false; } - FreeSql.Internal.CommonProvider.UpdateProvider.AuditDataValue(this, data, _db.Orm, _table, null); - var key = _db.Orm.GetEntityKeyString(_entityType, data, false); + FreeSql.Internal.CommonProvider.UpdateProvider.AuditDataValue(this, data, _db.OrmOriginal, _table, null); + var key = _db.OrmOriginal.GetEntityKeyString(_entityType, data, false); if (string.IsNullOrEmpty(key)) { - if (isThrow) throw new Exception($"不可更新,未设置主键的值:{_db.Orm.GetEntityString(_entityType, data)}"); + if (isThrow) throw new Exception($"不可更新,未设置主键的值:{_db.OrmOriginal.GetEntityString(_entityType, data)}"); return false; } if (_states.TryGetValue(key, out var tryval) == false) { - if (isThrow) throw new Exception($"不可更新,数据未被跟踪,应该先查询 或者 Attach:{_db.Orm.GetEntityString(_entityType, data)}"); + if (isThrow) throw new Exception($"不可更新,数据未被跟踪,应该先查询 或者 Attach:{_db.OrmOriginal.GetEntityString(_entityType, data)}"); return false; } return true; @@ -351,13 +351,13 @@ namespace FreeSql } if (_table.Primarys.Any() == false) { - if (isThrow) throw new Exception($"不可删除,实体没有主键:{_db.Orm.GetEntityString(_entityType, data)}"); + if (isThrow) throw new Exception($"不可删除,实体没有主键:{_db.OrmOriginal.GetEntityString(_entityType, data)}"); return false; } - var key = _db.Orm.GetEntityKeyString(_entityType, data, false); + var key = _db.OrmOriginal.GetEntityKeyString(_entityType, data, false); if (string.IsNullOrEmpty(key)) { - if (isThrow) throw new Exception($"不可删除,未设置主键的值:{_db.Orm.GetEntityString(_entityType, data)}"); + if (isThrow) throw new Exception($"不可删除,未设置主键的值:{_db.OrmOriginal.GetEntityString(_entityType, data)}"); return false; } //if (_states.TryGetValue(key, out var tryval) == false) { diff --git a/FreeSql.DbContext/DbSet/DbSetAsync.cs b/FreeSql.DbContext/DbSet/DbSetAsync.cs index 1dfb5296..1e756f53 100644 --- a/FreeSql.DbContext/DbSet/DbSetAsync.cs +++ b/FreeSql.DbContext/DbSet/DbSetAsync.cs @@ -35,7 +35,7 @@ namespace FreeSql if (_tableIdentitys.Length > 0) { //有自增,马上执行 - switch (_db.Orm.Ado.DataType) + switch (_db.OrmOriginal.Ado.DataType) { case DataType.SqlServer: case DataType.OdbcSqlServer: @@ -46,7 +46,7 @@ namespace FreeSql await DbContextExecCommandAsync(); var idtval = await this.OrmInsert(data).ExecuteIdentityAsync(); IncrAffrows(1); - _db.Orm.SetEntityIdentityValueWithPrimary(_entityType, data, idtval); + _db.OrmOriginal.SetEntityIdentityValueWithPrimary(_entityType, data, idtval); _db._entityChangeReport.Add(new DbContext.EntityChangeReport.ChangeInfo { Object = data, Type = DbContext.EntityChangeType.Insert }); Attach(data); if (_db.Options.EnableAddOrUpdateNavigateList) @@ -58,7 +58,7 @@ namespace FreeSql var newval = (await this.OrmInsert(data).ExecuteInsertedAsync()).First(); _db._entityChangeReport.Add(new DbContext.EntityChangeReport.ChangeInfo { Object = newval, Type = DbContext.EntityChangeType.Insert }); IncrAffrows(1); - _db.Orm.MapEntityValue(_entityType, newval, data); + _db.OrmOriginal.MapEntityValue(_entityType, newval, data); Attach(newval); if (_db.Options.EnableAddOrUpdateNavigateList) await AddOrUpdateNavigateListAsync(data, true); @@ -70,7 +70,7 @@ namespace FreeSql await DbContextExecCommandAsync(); var idtval = await this.OrmInsert(data).ExecuteIdentityAsync(); IncrAffrows(1); - _db.Orm.SetEntityIdentityValueWithPrimary(_entityType, data, idtval); + _db.OrmOriginal.SetEntityIdentityValueWithPrimary(_entityType, data, idtval); _db._entityChangeReport.Add(new DbContext.EntityChangeReport.ChangeInfo { Object = data, Type = DbContext.EntityChangeType.Insert }); Attach(data); if (_db.Options.EnableAddOrUpdateNavigateList) @@ -96,7 +96,7 @@ namespace FreeSql if (_tableIdentitys.Length > 0) { //有自增,马上执行 - switch (_db.Orm.Ado.DataType) + switch (_db.OrmOriginal.Ado.DataType) { case DataType.SqlServer: case DataType.OdbcSqlServer: @@ -104,11 +104,11 @@ namespace FreeSql case DataType.OdbcPostgreSQL: await DbContextExecCommandAsync(); var rets = await this.OrmInsert(data).ExecuteInsertedAsync(); - if (rets.Count != data.Count()) throw new Exception($"特别错误:批量添加失败,{_db.Orm.Ado.DataType} 的返回数据,与添加的数目不匹配"); + if (rets.Count != data.Count()) throw new Exception($"特别错误:批量添加失败,{_db.OrmOriginal.Ado.DataType} 的返回数据,与添加的数目不匹配"); _db._entityChangeReport.AddRange(rets.Select(a => new DbContext.EntityChangeReport.ChangeInfo { Object = a, Type = DbContext.EntityChangeType.Insert })); var idx = 0; foreach (var s in data) - _db.Orm.MapEntityValue(_entityType, rets[idx++], s); + _db.OrmOriginal.MapEntityValue(_entityType, rets[idx++], s); IncrAffrows(rets.Count); AttachRange(rets); if (_db.Options.EnableAddOrUpdateNavigateList) @@ -168,13 +168,13 @@ namespace FreeSql Expression.Constant( FreeSql.Internal.Utils.GetDataReaderValue( tref.Columns[colidx].CsType, - _db.Orm.GetEntityValueWithPropertyName(_table.Type, item, tref.Columns[colidx].CsName)), tref.RefColumns[colidx].CsType) + _db.OrmOriginal.GetEntityValueWithPropertyName(_table.Type, item, tref.Columns[colidx].CsName)), tref.RefColumns[colidx].CsType) ); if (whereParentExp == null) whereParentExp = whereExp; else whereParentExp = Expression.AndAlso(whereParentExp, whereExp); } var propValEach = GetItemValue(item, prop) as IEnumerable; - var subDelete = _db.Orm.Delete().AsType(tref.RefEntityType) + var subDelete = _db.OrmOriginal.Delete().AsType(tref.RefEntityType) .WithTransaction(_uow?.GetOrBeginTransaction()) .Where(Expression.Lambda>(whereParentExp, deleteWhereParentParam)); foreach (var propValItem in propValEach) @@ -230,12 +230,12 @@ namespace FreeSql Expression.Constant( FreeSql.Internal.Utils.GetDataReaderValue( tref.MiddleColumns[colidx].CsType, - _db.Orm.GetEntityValueWithPropertyName(_table.Type, item, tref.Columns[colidx].CsName)), tref.MiddleColumns[colidx].CsType) + _db.OrmOriginal.GetEntityValueWithPropertyName(_table.Type, item, tref.Columns[colidx].CsName)), tref.MiddleColumns[colidx].CsType) ), midSelectParam)); if (curList.Any() == false) //全部删除 { - var delall = _db.Orm.Delete().AsType(tref.RefMiddleEntityType) + var delall = _db.OrmOriginal.Delete().AsType(tref.RefMiddleEntityType) .WithTransaction(_uow?.GetOrBeginTransaction()); foreach (var midWhere in midWheres) delall.Where(midWhere); var sql = delall.ToSql(); @@ -266,8 +266,8 @@ namespace FreeSql for (var midcolidx = tref.Columns.Count; midcolidx < tref.MiddleColumns.Count; midcolidx++) { var refcol = tref.Columns[midcolidx - tref.Columns.Count]; - var midval = FreeSql.Internal.Utils.GetDataReaderValue(refcol.CsType, _db.Orm.GetEntityValueWithPropertyName(tref.RefMiddleEntityType, midItem, tref.MiddleColumns[midcolidx].CsName)); - var refval = FreeSql.Internal.Utils.GetDataReaderValue(refcol.CsType, _db.Orm.GetEntityValueWithPropertyName(tref.RefEntityType, curList[curIdx], tref.Columns[midcolidx - tref.Columns.Count].CsName)); + var midval = FreeSql.Internal.Utils.GetDataReaderValue(refcol.CsType, _db.OrmOriginal.GetEntityValueWithPropertyName(tref.RefMiddleEntityType, midItem, tref.MiddleColumns[midcolidx].CsName)); + var refval = FreeSql.Internal.Utils.GetDataReaderValue(refcol.CsType, _db.OrmOriginal.GetEntityValueWithPropertyName(tref.RefEntityType, curList[curIdx], tref.Columns[midcolidx - tref.Columns.Count].CsName)); if (object.Equals(midval, refval) == false) { isEquals = false; @@ -289,14 +289,14 @@ namespace FreeSql var newItem = Activator.CreateInstance(tref.RefMiddleEntityType); for (var colidx = 0; colidx < tref.Columns.Count; colidx++) { - var val = FreeSql.Internal.Utils.GetDataReaderValue(tref.MiddleColumns[colidx].CsType, _db.Orm.GetEntityValueWithPropertyName(_table.Type, item, tref.Columns[colidx].CsName)); - _db.Orm.SetEntityValueWithPropertyName(tref.RefMiddleEntityType, newItem, tref.MiddleColumns[colidx].CsName, val); + var val = FreeSql.Internal.Utils.GetDataReaderValue(tref.MiddleColumns[colidx].CsType, _db.OrmOriginal.GetEntityValueWithPropertyName(_table.Type, item, tref.Columns[colidx].CsName)); + _db.OrmOriginal.SetEntityValueWithPropertyName(tref.RefMiddleEntityType, newItem, tref.MiddleColumns[colidx].CsName, val); } for (var midcolidx = tref.Columns.Count; midcolidx < tref.MiddleColumns.Count; midcolidx++) { var refcol = tref.RefColumns[midcolidx - tref.Columns.Count]; - var refval = FreeSql.Internal.Utils.GetDataReaderValue(tref.MiddleColumns[midcolidx].CsType, _db.Orm.GetEntityValueWithPropertyName(tref.RefEntityType, curItem, refcol.CsName)); - _db.Orm.SetEntityValueWithPropertyName(tref.RefMiddleEntityType, newItem, tref.MiddleColumns[midcolidx].CsName, refval); + var refval = FreeSql.Internal.Utils.GetDataReaderValue(tref.MiddleColumns[midcolidx].CsType, _db.OrmOriginal.GetEntityValueWithPropertyName(tref.RefEntityType, curItem, refcol.CsName)); + _db.OrmOriginal.SetEntityValueWithPropertyName(tref.RefMiddleEntityType, newItem, tref.MiddleColumns[midcolidx].CsName, refval); } midListAdd.Add(newItem); } @@ -308,8 +308,8 @@ namespace FreeSql { for (var colidx = 0; colidx < tref.Columns.Count; colidx++) { - var val = FreeSql.Internal.Utils.GetDataReaderValue(tref.RefColumns[colidx].CsType, _db.Orm.GetEntityValueWithPropertyName(_table.Type, item, tref.Columns[colidx].CsName)); - _db.Orm.SetEntityValueWithPropertyName(tref.RefEntityType, propValItem, tref.RefColumns[colidx].CsName, val); + var val = FreeSql.Internal.Utils.GetDataReaderValue(tref.RefColumns[colidx].CsType, _db.OrmOriginal.GetEntityValueWithPropertyName(_table.Type, item, tref.Columns[colidx].CsName)); + _db.OrmOriginal.SetEntityValueWithPropertyName(tref.RefEntityType, propValItem, tref.RefColumns[colidx].CsName, val); } await refSet.AddOrUpdateAsync(propValItem); } @@ -336,10 +336,10 @@ namespace FreeSql if (_states.TryGetValue(uplst1.Key, out var lstval1) == false) return -999; var lstval2 = default(EntityState); - if (uplst2 != null && _states.TryGetValue(uplst2.Key, out lstval2) == false) throw new Exception($"特别错误:更新失败,数据未被跟踪:{_db.Orm.GetEntityString(_entityType, uplst2.Value)}"); + if (uplst2 != null && _states.TryGetValue(uplst2.Key, out lstval2) == false) throw new Exception($"特别错误:更新失败,数据未被跟踪:{_db.OrmOriginal.GetEntityString(_entityType, uplst2.Value)}"); - var cuig1 = _db.Orm.CompareEntityValueReturnColumns(_entityType, uplst1.Value, lstval1.Value, true); - var cuig2 = uplst2 != null ? _db.Orm.CompareEntityValueReturnColumns(_entityType, uplst2.Value, lstval2.Value, true) : null; + var cuig1 = _db.OrmOriginal.CompareEntityValueReturnColumns(_entityType, uplst1.Value, lstval1.Value, true); + var cuig2 = uplst2 != null ? _db.OrmOriginal.CompareEntityValueReturnColumns(_entityType, uplst2.Value, lstval2.Value, true) : null; List data = null; string[] cuig = null; @@ -372,9 +372,9 @@ namespace FreeSql foreach (var newval in data) { if (_states.TryGetValue(newval.Key, out var tryold)) - _db.Orm.MapEntityValue(_entityType, newval.Value, tryold.Value); + _db.OrmOriginal.MapEntityValue(_entityType, newval.Value, tryold.Value); if (newval.OldValue != null) - _db.Orm.MapEntityValue(_entityType, newval.Value, newval.OldValue); + _db.OrmOriginal.MapEntityValue(_entityType, newval.Value, newval.OldValue); } return affrows; } @@ -385,11 +385,11 @@ namespace FreeSql async public Task UpdateAsync(TEntity data) { var exists = ExistsInStates(data); - if (exists == null) throw new Exception($"不可更新,未设置主键的值:{_db.Orm.GetEntityString(_entityType, data)}"); + if (exists == null) throw new Exception($"不可更新,未设置主键的值:{_db.OrmOriginal.GetEntityString(_entityType, data)}"); if (exists == false) { var olddata = await OrmSelect(data).FirstAsync(); - if (olddata == null) throw new Exception($"不可更新,数据库不存在该记录:{_db.Orm.GetEntityString(_entityType, data)}"); + if (olddata == null) throw new Exception($"不可更新,数据库不存在该记录:{_db.OrmOriginal.GetEntityString(_entityType, data)}"); } await UpdateRangePrivAsync(new[] { data }, true); @@ -438,7 +438,7 @@ namespace FreeSql async public Task AddOrUpdateAsync(TEntity data) { if (data == null) throw new ArgumentNullException(nameof(data)); - if (_table.Primarys.Any() == false) throw new Exception($"不可添加,实体没有主键:{_db.Orm.GetEntityString(_entityType, data)}"); + if (_table.Primarys.Any() == false) throw new Exception($"不可添加,实体没有主键:{_db.OrmOriginal.GetEntityString(_entityType, data)}"); var flagExists = ExistsInStates(data); if (flagExists == false) @@ -458,7 +458,7 @@ namespace FreeSql } if (CanAdd(data, false)) { - _db.Orm.ClearEntityPrimaryValueWithIdentity(_entityType, data); + _db.OrmOriginal.ClearEntityPrimaryValueWithIdentity(_entityType, data); await AddPrivAsync(data, false); } } diff --git a/FreeSql.DbContext/DbSet/DbSetSync.cs b/FreeSql.DbContext/DbSet/DbSetSync.cs index 79171465..b49f5542 100644 --- a/FreeSql.DbContext/DbSet/DbSetSync.cs +++ b/FreeSql.DbContext/DbSet/DbSetSync.cs @@ -34,7 +34,7 @@ namespace FreeSql if (_tableIdentitys.Length > 0) { //有自增,马上执行 - switch (_db.Orm.Ado.DataType) + switch (_db.OrmOriginal.Ado.DataType) { case DataType.SqlServer: case DataType.OdbcSqlServer: @@ -45,7 +45,7 @@ namespace FreeSql DbContextExecCommand(); var idtval = this.OrmInsert(data).ExecuteIdentity(); IncrAffrows(1); - _db.Orm.SetEntityIdentityValueWithPrimary(_entityType, data, idtval); + _db.OrmOriginal.SetEntityIdentityValueWithPrimary(_entityType, data, idtval); _db._entityChangeReport.Add(new DbContext.EntityChangeReport.ChangeInfo { Object = data, Type = DbContext.EntityChangeType.Insert }); Attach(data); if (_db.Options.EnableAddOrUpdateNavigateList) @@ -57,7 +57,7 @@ namespace FreeSql var newval = this.OrmInsert(data).ExecuteInserted().First(); _db._entityChangeReport.Add(new DbContext.EntityChangeReport.ChangeInfo { Object = newval, Type = DbContext.EntityChangeType.Insert }); IncrAffrows(1); - _db.Orm.MapEntityValue(_entityType, newval, data); + _db.OrmOriginal.MapEntityValue(_entityType, newval, data); Attach(newval); if (_db.Options.EnableAddOrUpdateNavigateList) AddOrUpdateNavigateList(data, true); @@ -69,7 +69,7 @@ namespace FreeSql DbContextExecCommand(); var idtval = this.OrmInsert(data).ExecuteIdentity(); IncrAffrows(1); - _db.Orm.SetEntityIdentityValueWithPrimary(_entityType, data, idtval); + _db.OrmOriginal.SetEntityIdentityValueWithPrimary(_entityType, data, idtval); _db._entityChangeReport.Add(new DbContext.EntityChangeReport.ChangeInfo { Object = data, Type = DbContext.EntityChangeType.Insert }); Attach(data); if (_db.Options.EnableAddOrUpdateNavigateList) @@ -99,7 +99,7 @@ namespace FreeSql if (_tableIdentitys.Length > 0) { //有自增,马上执行 - switch (_db.Orm.Ado.DataType) + switch (_db.OrmOriginal.Ado.DataType) { case DataType.SqlServer: case DataType.OdbcSqlServer: @@ -107,11 +107,11 @@ namespace FreeSql case DataType.OdbcPostgreSQL: DbContextExecCommand(); var rets = this.OrmInsert(data).ExecuteInserted(); - if (rets.Count != data.Count()) throw new Exception($"特别错误:批量添加失败,{_db.Orm.Ado.DataType} 的返回数据,与添加的数目不匹配"); + if (rets.Count != data.Count()) throw new Exception($"特别错误:批量添加失败,{_db.OrmOriginal.Ado.DataType} 的返回数据,与添加的数目不匹配"); _db._entityChangeReport.AddRange(rets.Select(a => new DbContext.EntityChangeReport.ChangeInfo { Object = a, Type = DbContext.EntityChangeType.Insert })); var idx = 0; foreach (var s in data) - _db.Orm.MapEntityValue(_entityType, rets[idx++], s); + _db.OrmOriginal.MapEntityValue(_entityType, rets[idx++], s); IncrAffrows(rets.Count); AttachRange(rets); if (_db.Options.EnableAddOrUpdateNavigateList) @@ -180,13 +180,13 @@ namespace FreeSql Expression.Constant( FreeSql.Internal.Utils.GetDataReaderValue( tref.Columns[colidx].CsType, - _db.Orm.GetEntityValueWithPropertyName(_table.Type, item, tref.Columns[colidx].CsName)), tref.RefColumns[colidx].CsType) + _db.OrmOriginal.GetEntityValueWithPropertyName(_table.Type, item, tref.Columns[colidx].CsName)), tref.RefColumns[colidx].CsType) ); if (whereParentExp == null) whereParentExp = whereExp; else whereParentExp = Expression.AndAlso(whereParentExp, whereExp); } var propValEach = GetItemValue(item, prop) as IEnumerable; - var subDelete = _db.Orm.Delete().AsType(tref.RefEntityType) + var subDelete = _db.OrmOriginal.Delete().AsType(tref.RefEntityType) .WithTransaction(_uow?.GetOrBeginTransaction()) .Where(Expression.Lambda>(whereParentExp, deleteWhereParentParam)); foreach (var propValItem in propValEach) @@ -242,13 +242,13 @@ namespace FreeSql Expression.Constant( FreeSql.Internal.Utils.GetDataReaderValue( tref.MiddleColumns[colidx].CsType, - _db.Orm.GetEntityValueWithPropertyName(_table.Type, item, tref.Columns[colidx].CsName)), tref.MiddleColumns[colidx].CsType) + _db.OrmOriginal.GetEntityValueWithPropertyName(_table.Type, item, tref.Columns[colidx].CsName)), tref.MiddleColumns[colidx].CsType) ), midSelectParam)); if (curList.Any() == false) //全部删除 { - var delall = _db.Orm.Delete().AsType(tref.RefMiddleEntityType) - .WithTransaction(_uow?.GetOrBeginTransaction()); + var delall = _db.OrmOriginal.Delete().AsType(tref.RefMiddleEntityType) + .WithTransaction(_uow?.GetOrBeginTransaction()); foreach (var midWhere in midWheres) delall.Where(midWhere); var sql = delall.ToSql(); delall.ExecuteAffrows(); @@ -278,8 +278,8 @@ namespace FreeSql for (var midcolidx = tref.Columns.Count; midcolidx < tref.MiddleColumns.Count; midcolidx++) { var refcol = tref.RefColumns[midcolidx - tref.Columns.Count]; - var midval = FreeSql.Internal.Utils.GetDataReaderValue(refcol.CsType, _db.Orm.GetEntityValueWithPropertyName(tref.RefMiddleEntityType, midItem, tref.MiddleColumns[midcolidx].CsName)); - var refval = FreeSql.Internal.Utils.GetDataReaderValue(refcol.CsType, _db.Orm.GetEntityValueWithPropertyName(tref.RefEntityType, curList[curIdx], refcol.CsName)); + var midval = FreeSql.Internal.Utils.GetDataReaderValue(refcol.CsType, _db.OrmOriginal.GetEntityValueWithPropertyName(tref.RefMiddleEntityType, midItem, tref.MiddleColumns[midcolidx].CsName)); + var refval = FreeSql.Internal.Utils.GetDataReaderValue(refcol.CsType, _db.OrmOriginal.GetEntityValueWithPropertyName(tref.RefEntityType, curList[curIdx], refcol.CsName)); if (object.Equals(midval, refval) == false) { isEquals = false; @@ -301,14 +301,14 @@ namespace FreeSql var newItem = Activator.CreateInstance(tref.RefMiddleEntityType); for (var colidx = 0; colidx < tref.Columns.Count; colidx++) { - var val = FreeSql.Internal.Utils.GetDataReaderValue(tref.MiddleColumns[colidx].CsType, _db.Orm.GetEntityValueWithPropertyName(_table.Type, item, tref.Columns[colidx].CsName)); - _db.Orm.SetEntityValueWithPropertyName(tref.RefMiddleEntityType, newItem, tref.MiddleColumns[colidx].CsName, val); + var val = FreeSql.Internal.Utils.GetDataReaderValue(tref.MiddleColumns[colidx].CsType, _db.OrmOriginal.GetEntityValueWithPropertyName(_table.Type, item, tref.Columns[colidx].CsName)); + _db.OrmOriginal.SetEntityValueWithPropertyName(tref.RefMiddleEntityType, newItem, tref.MiddleColumns[colidx].CsName, val); } for (var midcolidx = tref.Columns.Count; midcolidx < tref.MiddleColumns.Count; midcolidx++) { var refcol = tref.RefColumns[midcolidx - tref.Columns.Count]; - var refval = FreeSql.Internal.Utils.GetDataReaderValue(tref.MiddleColumns[midcolidx].CsType, _db.Orm.GetEntityValueWithPropertyName(tref.RefEntityType, curItem, refcol.CsName)); - _db.Orm.SetEntityValueWithPropertyName(tref.RefMiddleEntityType, newItem, tref.MiddleColumns[midcolidx].CsName, refval); + var refval = FreeSql.Internal.Utils.GetDataReaderValue(tref.MiddleColumns[midcolidx].CsType, _db.OrmOriginal.GetEntityValueWithPropertyName(tref.RefEntityType, curItem, refcol.CsName)); + _db.OrmOriginal.SetEntityValueWithPropertyName(tref.RefMiddleEntityType, newItem, tref.MiddleColumns[midcolidx].CsName, refval); } midListAdd.Add(newItem); } @@ -320,8 +320,8 @@ namespace FreeSql { for (var colidx = 0; colidx < tref.Columns.Count; colidx++) { - var val = FreeSql.Internal.Utils.GetDataReaderValue(tref.RefColumns[colidx].CsType, _db.Orm.GetEntityValueWithPropertyName(_table.Type, item, tref.Columns[colidx].CsName)); - _db.Orm.SetEntityValueWithPropertyName(tref.RefEntityType, propValItem, tref.RefColumns[colidx].CsName, val); + var val = FreeSql.Internal.Utils.GetDataReaderValue(tref.RefColumns[colidx].CsType, _db.OrmOriginal.GetEntityValueWithPropertyName(_table.Type, item, tref.Columns[colidx].CsName)); + _db.OrmOriginal.SetEntityValueWithPropertyName(tref.RefEntityType, propValItem, tref.RefColumns[colidx].CsName, val); } refSet.AddOrUpdate(propValItem); } @@ -371,10 +371,10 @@ namespace FreeSql if (_states.TryGetValue(uplst1.Key, out var lstval1) == false) return -999; var lstval2 = default(EntityState); - if (uplst2 != null && _states.TryGetValue(uplst2.Key, out lstval2) == false) throw new Exception($"特别错误:更新失败,数据未被跟踪:{_db.Orm.GetEntityString(_entityType, uplst2.Value)}"); + if (uplst2 != null && _states.TryGetValue(uplst2.Key, out lstval2) == false) throw new Exception($"特别错误:更新失败,数据未被跟踪:{_db.OrmOriginal.GetEntityString(_entityType, uplst2.Value)}"); - var cuig1 = _db.Orm.CompareEntityValueReturnColumns(_entityType, uplst1.Value, lstval1.Value, true); - var cuig2 = uplst2 != null ? _db.Orm.CompareEntityValueReturnColumns(_entityType, uplst2.Value, lstval2.Value, true) : null; + var cuig1 = _db.OrmOriginal.CompareEntityValueReturnColumns(_entityType, uplst1.Value, lstval1.Value, true); + var cuig2 = uplst2 != null ? _db.OrmOriginal.CompareEntityValueReturnColumns(_entityType, uplst2.Value, lstval2.Value, true) : null; List data = null; string[] cuig = null; @@ -407,9 +407,9 @@ namespace FreeSql foreach (var newval in data) { if (_states.TryGetValue(newval.Key, out var tryold)) - _db.Orm.MapEntityValue(_entityType, newval.Value, tryold.Value); + _db.OrmOriginal.MapEntityValue(_entityType, newval.Value, tryold.Value); if (newval.OldValue != null) - _db.Orm.MapEntityValue(_entityType, newval.Value, newval.OldValue); + _db.OrmOriginal.MapEntityValue(_entityType, newval.Value, newval.OldValue); } return affrows; } @@ -426,11 +426,11 @@ namespace FreeSql public void Update(TEntity data) { var exists = ExistsInStates(data); - if (exists == null) throw new Exception($"不可更新,未设置主键的值:{_db.Orm.GetEntityString(_entityType, data)}"); + if (exists == null) throw new Exception($"不可更新,未设置主键的值:{_db.OrmOriginal.GetEntityString(_entityType, data)}"); if (exists == false) { var olddata = OrmSelect(data).First(); - if (olddata == null) throw new Exception($"不可更新,数据库不存在该记录:{_db.Orm.GetEntityString(_entityType, data)}"); + if (olddata == null) throw new Exception($"不可更新,数据库不存在该记录:{_db.OrmOriginal.GetEntityString(_entityType, data)}"); } UpdateRangePriv(new[] { data }, true); @@ -476,7 +476,7 @@ namespace FreeSql { var state = CreateEntityState(item); _states.TryRemove(state.Key, out var trystate); - _db.Orm.ClearEntityPrimaryValueWithIdentityAndGuid(_entityType, item); + _db.OrmOriginal.ClearEntityPrimaryValueWithIdentityAndGuid(_entityType, item); EnqueueToDbContext(DbContext.EntityChangeType.Delete, state); } @@ -501,7 +501,7 @@ namespace FreeSql public void AddOrUpdate(TEntity data) { if (data == null) throw new ArgumentNullException(nameof(data)); - if (_table.Primarys.Any() == false) throw new Exception($"不可添加,实体没有主键:{_db.Orm.GetEntityString(_entityType, data)}"); + if (_table.Primarys.Any() == false) throw new Exception($"不可添加,实体没有主键:{_db.OrmOriginal.GetEntityString(_entityType, data)}"); var flagExists = ExistsInStates(data); if (flagExists == false) @@ -521,7 +521,7 @@ namespace FreeSql } if (CanAdd(data, false)) { - _db.Orm.ClearEntityPrimaryValueWithIdentity(_entityType, data); + _db.OrmOriginal.ClearEntityPrimaryValueWithIdentity(_entityType, data); AddPriv(data, false); } } diff --git a/FreeSql.DbContext/Extensions/DependencyInjection.cs b/FreeSql.DbContext/Extensions/DependencyInjection.cs index c22b4ee8..6e7fb6cd 100644 --- a/FreeSql.DbContext/Extensions/DependencyInjection.cs +++ b/FreeSql.DbContext/Extensions/DependencyInjection.cs @@ -23,14 +23,14 @@ namespace FreeSql { throw new Exception($"AddFreeDbContext 发生错误,请检查 {dbContextType.Name} 的构造参数都已正确注入", ex); } - if (ctx != null && ctx._ormPriv == null) + if (ctx != null && ctx._ormScoped == null) { var builder = new DbContextOptionsBuilder(); options(builder); - ctx._ormPriv = builder._fsql; + ctx._ormScoped = DbContextScopedFreeSql.Create(builder._fsql, () => ctx, () => ctx.UnitOfWork); ctx._optionsPriv = builder._options; - if (ctx._ormPriv == null) + if (ctx._ormScoped == null) throw new Exception("请在 OnConfiguring 或 AddFreeDbContext 中配置 UseFreeSql"); ctx.InitPropSets(); diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index eacd506b..165be8ac 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -4,12 +4,6 @@ FreeSql.DbContext - - - 注意:IFreeSql 属于顶级对象,事务无法自动传递。 - 手工传递事务:ISelect/IInsert/IDelete/IUpdate 可以使用 WithTransaction(uow.GetOrBeginTransaction()) - - 添加 @@ -231,12 +225,6 @@ - - - 注意:IFreeSql 属于顶级对象,事务无法自动传递。 - 手工传递事务:ISelect/IInsert/IDelete/IUpdate 可以使用 WithTransaction(uow.GetOrBeginTransaction()) - - 动态Type,在使用 Repository<object> 后使用本方法,指定实体类型 diff --git a/FreeSql.DbContext/Repository/ContextSet/RepositoryDbContext.cs b/FreeSql.DbContext/Repository/ContextSet/RepositoryDbContext.cs index 8945b6fa..7638d46d 100644 --- a/FreeSql.DbContext/Repository/ContextSet/RepositoryDbContext.cs +++ b/FreeSql.DbContext/Repository/ContextSet/RepositoryDbContext.cs @@ -11,7 +11,7 @@ namespace FreeSql protected IBaseRepository _repo; public RepositoryDbContext(IFreeSql orm, IBaseRepository repo) : base() { - _ormPriv = orm; + _ormScoped = DbContextScopedFreeSql.Create(orm, () => this, () => repo.UnitOfWork); _isUseUnitOfWork = false; UnitOfWork = repo.UnitOfWork; _repo = repo; @@ -23,7 +23,7 @@ namespace FreeSql { if (_dicSet.ContainsKey(entityType)) return _dicSet[entityType]; - var tb = _ormPriv.CodeFirst.GetTableByEntity(entityType); + var tb = OrmOriginal.CodeFirst.GetTableByEntity(entityType); if (tb == null) return null; object repo = _repo; diff --git a/FreeSql.DbContext/Repository/ContextSet/RepositoryDbSet.cs b/FreeSql.DbContext/Repository/ContextSet/RepositoryDbSet.cs index 2b33cf57..55db9b9f 100644 --- a/FreeSql.DbContext/Repository/ContextSet/RepositoryDbSet.cs +++ b/FreeSql.DbContext/Repository/ContextSet/RepositoryDbSet.cs @@ -34,7 +34,7 @@ namespace FreeSql if (entitys != null) foreach (var entity in entitys) if (filter.Value.ExpressionDelegate?.Invoke(entity) == false) - throw new Exception($"FreeSql.Repository Update 失败,因为设置了过滤器 {filter.Key}: {filter.Value.Expression},更新的数据不符合 {_db.Orm.GetEntityString(_entityType, entity)}"); + throw new Exception($"FreeSql.Repository Update 失败,因为设置了过滤器 {filter.Key}: {filter.Value.Expression},更新的数据不符合 {_db.OrmOriginal.GetEntityString(_entityType, entity)}"); update.Where(filter.Value.Expression); } return update.AsTable(_repo.AsTableValueInternal); @@ -58,7 +58,7 @@ namespace FreeSql if (entitys != null) foreach (var entity in entitys) if (filter.Value.ExpressionDelegate?.Invoke(entity) == false) - throw new Exception($"FreeSql.Repository Insert 失败,因为设置了过滤器 {filter.Key}: {filter.Value.Expression},插入的数据不符合 {_db.Orm.GetEntityString(_entityType, entity)}"); + throw new Exception($"FreeSql.Repository Insert 失败,因为设置了过滤器 {filter.Key}: {filter.Value.Expression},插入的数据不符合 {_db.OrmOriginal.GetEntityString(_entityType, entity)}"); } return insert.AsTable(_repo.AsTableValueInternal); } diff --git a/FreeSql.DbContext/Repository/Repository/BaseRepository.cs b/FreeSql.DbContext/Repository/Repository/BaseRepository.cs index 0670666f..de6d38f4 100644 --- a/FreeSql.DbContext/Repository/Repository/BaseRepository.cs +++ b/FreeSql.DbContext/Repository/Repository/BaseRepository.cs @@ -13,7 +13,7 @@ namespace FreeSql { internal RepositoryDbContext _dbPriv; //这个不能私有化,有地方需要反射获取它 - internal RepositoryDbContext _db => _dbPriv ?? (_dbPriv = new RepositoryDbContext(Orm, this)); + internal RepositoryDbContext _db => _dbPriv ?? (_dbPriv = new RepositoryDbContext(OrmOriginal, this)); internal RepositoryDbSet _dbsetPriv; internal RepositoryDbSet _dbset => _dbsetPriv ?? (_dbsetPriv = _db.Set() as RepositoryDbSet); @@ -25,7 +25,7 @@ namespace FreeSql protected BaseRepository(IFreeSql fsql, Expression> filter, Func asTable = null) { - Orm = fsql; + _ormScoped = DbContextScopedFreeSql.Create(fsql, () => _db, () => UnitOfWork); DataFilterUtil.SetRepositoryDataFilter(this, null); DataFilter.Apply("", filter); AsTable(asTable); @@ -56,7 +56,9 @@ namespace FreeSql } public DbContextOptions DbContextOptions { get => _db.Options; set => _db.Options = value; } - public IFreeSql Orm { get; private set; } + internal DbContextScopedFreeSql _ormScoped; + internal IFreeSql OrmOriginal => _ormScoped?._originalFsql; + public IFreeSql Orm => _ormScoped; IUnitOfWork _unitOfWork; public IUnitOfWork UnitOfWork { @@ -64,6 +66,7 @@ namespace FreeSql { _unitOfWork = value; if (_dbsetPriv != null) _dbsetPriv._uow = _unitOfWork; //防止 dbset 对象已经存在,再次设置 UnitOfWork 无法生效,所以作此判断重新设置 + if (_dbPriv != null) _dbPriv.UnitOfWork = _unitOfWork; } get => _unitOfWork; } @@ -147,11 +150,11 @@ namespace FreeSql TEntity CheckTKeyAndReturnIdEntity(TKey id) { - var tb = _db.Orm.CodeFirst.GetTableByEntity(EntityType); + var tb = _db.OrmOriginal.CodeFirst.GetTableByEntity(EntityType); if (tb.Primarys.Length != 1) throw new Exception($"实体类型 {EntityType.Name} 主键数量不为 1,无法使用该方法"); if (tb.Primarys[0].CsType.NullableTypeOrThis() != typeof(TKey).NullableTypeOrThis()) throw new Exception($"实体类型 {EntityType.Name} 主键类型不为 {typeof(TKey).FullName},无法使用该方法"); var obj = Activator.CreateInstance(tb.Type); - _db.Orm.SetEntityValueWithPropertyName(tb.Type, obj, tb.Primarys[0].CsName, id); + _db.OrmOriginal.SetEntityValueWithPropertyName(tb.Type, obj, tb.Primarys[0].CsName, id); var ret = obj as TEntity; if (ret == null) throw new Exception($"实体类型 {EntityType.Name} 无法转换为 {typeof(TEntity).Name},无法使用该方法"); return ret; diff --git a/FreeSql.DbContext/Repository/Repository/IBaseRepository.cs b/FreeSql.DbContext/Repository/Repository/IBaseRepository.cs index db8c71a0..e172073f 100644 --- a/FreeSql.DbContext/Repository/Repository/IBaseRepository.cs +++ b/FreeSql.DbContext/Repository/Repository/IBaseRepository.cs @@ -10,11 +10,6 @@ namespace FreeSql { Type EntityType { get; } IUnitOfWork UnitOfWork { get; set; } - - /// - /// 注意:IFreeSql 属于顶级对象,事务无法自动传递。 - /// 手工传递事务:ISelect/IInsert/IDelete/IUpdate 可以使用 WithTransaction(uow.GetOrBeginTransaction()) - /// IFreeSql Orm { get; } /// diff --git a/FreeSql.Tests/FreeSql.Tests.DbContext/RepositoryTests.cs b/FreeSql.Tests/FreeSql.Tests.DbContext/RepositoryTests.cs index d6dca944..0797327d 100644 --- a/FreeSql.Tests/FreeSql.Tests.DbContext/RepositoryTests.cs +++ b/FreeSql.Tests/FreeSql.Tests.DbContext/RepositoryTests.cs @@ -29,6 +29,13 @@ namespace FreeSql.Tests item = repos.Find(item.Id); Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(item)); + + repos.Orm.Insert(new AddUpdateInfo()).ExecuteAffrows(); + repos.Orm.Insert(new AddUpdateInfo { Id = Guid.NewGuid() }).ExecuteAffrows(); + repos.Orm.Update().Set(a => a.Title == "xxx").Where(a => a.Id == item.Id).ExecuteAffrows(); + item = repos.Orm.Select(item).First(); + Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(item)); + repos.Orm.Delete(item).ExecuteAffrows(); } [Fact] @@ -122,6 +129,7 @@ namespace FreeSql.Tests { flowRepos = uow.GetRepository(); flowRepos.Insert(flow); + flowRepos.Orm.Select().ToList(); uow.Commit(); } } @@ -158,6 +166,7 @@ namespace FreeSql.Tests uow.Close(); var uowFlowRepos = uow.GetRepository(); uowFlowRepos.Insert(flow); + uowFlowRepos.Orm.Select().ToList(); //ѹرչԪ᲻ύûӰ죬˴עȷԪǷЧرˣCommitҲӦò //uow.Commit(); } @@ -199,6 +208,7 @@ namespace FreeSql.Tests { var uowFlowRepos = uow.GetRepository(); uowFlowRepos.Insert(flow); + uowFlowRepos.Orm.Select().ToList(); // Insert/Update/Delete ùرuowķᷢ쳣 uow.Close(); uow.Commit(); @@ -240,6 +250,7 @@ namespace FreeSql.Tests { var uowFlowRepos = uow.GetRepository(); uowFlowRepos.Insert(flow); + uowFlowRepos.Orm.Select().ToList(); //commitύݿ //uow.Commit(); } diff --git a/FreeSql.Tests/FreeSql.Tests.DbContext/UnitTest1.cs b/FreeSql.Tests/FreeSql.Tests.DbContext/UnitTest1.cs index f01f8158..17f73605 100644 --- a/FreeSql.Tests/FreeSql.Tests.DbContext/UnitTest1.cs +++ b/FreeSql.Tests/FreeSql.Tests.DbContext/UnitTest1.cs @@ -118,6 +118,8 @@ namespace FreeSql.Tests }; ctx.AddRange(new[] { song1, song2, song3 }); + ctx.Orm.Select().Limit(10).ToList(); + ctx.AddRange( new[] { new Song_tag { Song_id = song1.Id, Tag_id = tag1.Id }, @@ -150,7 +152,7 @@ namespace FreeSql.Tests using (var ctx = g.sqlite.CreateDbContext()) { - + ctx.Options.EnableAddOrUpdateNavigateList = true; var tags = ctx.Set().Select.IncludeMany(a => a.Tags).ToList(); var tag = new Tag @@ -168,6 +170,9 @@ namespace FreeSql.Tests } }; ctx.Add(tag); + + var tags2 = ctx.Orm.Select().IncludeMany(a => a.Tags).ToList(); + ctx.SaveChanges(); } } @@ -179,10 +184,12 @@ namespace FreeSql.Tests using (var ctx = g.sqlite.CreateDbContext()) { - + ctx.Options.EnableAddOrUpdateNavigateList = true; var tag = ctx.Set().Select.First(); tag.Tags.Add(new Tag { Name = "sub3" }); + tag.Name = Guid.NewGuid().ToString(); ctx.Update(tag); + var xxx = ctx.Orm.Select().First(); ctx.SaveChanges(); } } diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index 7783e259..12b3cc3e 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -1,3708 +1,3669 @@ - - - - FreeSql - - - - - 数据库列名 - - - - - 指定数据库旧的列名,修改实体属性命名时,同时设置此参数为修改之前的值,CodeFirst才可以正确修改数据库字段;否则将视为【新增字段】 - - - - - 数据库类型,如: varchar(255) - 字符串长度,可使用特性 [MaxLength(255)] - - - - - 主键 - - - - - 自增标识 - - - - - 是否可DBNull - - - - - 忽略此列,不迁移、不插入 - - - - - 设置行锁(乐观锁)版本号,每次更新累加版本号,若更新整个实体时会附带当前的版本号判断(修改失败时抛出异常) - - - - - 类型映射,除了可做基本的类型映射外,特别介绍的功能: - 1、将 enum 属性映射成 typeof(string) - 2、将 对象 属性映射成 typeof(string),请安装扩展包 FreeSql.Extensions.JsonMap - - - - - 创建表时字段的位置(场景:实体继承后设置字段顺序),规则如下: - - >0时排前面,1,2,3... - - =0时排中间(默认) - - <0时排后面,...-3,-2,-1 - - - - - 该字段是否可以插入,默认值true,指定为false插入时该字段会被忽略 - - - - - 该字段是否可以更新,默认值true,指定为false更新时该字段会被忽略 - - - - - 标记属性为数据库服务器时间(utc/local),在插入的时候使用类似 getdate() 执行 - - - - - 设置长度,针对 string 类型避免 DbType 的繁琐设置 - 提示:也可以使用 [MaxLength(100)] - --- - StringLength = 100 时,对应 DbType: - MySql -> varchar(100) - SqlServer -> nvarchar(100) - PostgreSQL -> varchar(100) - Oracle -> nvarchar2(100) - Sqlite -> nvarchar(100) - --- - StringLength = -1 时,对应 DbType: - MySql -> text - SqlServer -> nvarchar(max) - PostgreSQL -> text - Oracle -> nvarchar2(4000) - Sqlite -> text - - - - - 执行 Insert 方法时使用此值 - 注意:如果是 getdate() 这种请可考虑使用 ServerTime,因为它对数据库间作了适配 - - - - - 数据库列名 - - - - - 指定数据库旧的列名,修改实体属性命名时,同时设置此参数为修改之前的值,CodeFirst才可以正确修改数据库字段;否则将视为【新增字段】 - - - - - 数据库类型,如: varchar(255) - - - - - 主键 - - - - - 自增标识 - - - - - 是否可DBNull - - - - - 忽略此列,不迁移、不插入 - - - - - 乐观锁 - - - - - 类型映射,比如:可将 enum 属性映射成 typeof(string) - - - - - - - 创建表时字段位置,规则如下: - - >0时排前面 - - =0时排中间(默认) - - <0时排后面 - - - - - - - 该字段是否可以插入,默认值true,指定为false插入时该字段会被忽略 - - - - - - - 该字段是否可以更新,默认值true,指定为false更新时该字段会被忽略 - - - - - - - 标记属性为数据库服务器时间(utc/local),在插入的时候使用类似 getdate() 执行 - - - - - - - 设置长度,针对 string 类型避免 DbType 的繁琐设置 - --- - StringLength = 100 时,对应 DbType: - MySql -> varchar(100) - SqlServer -> nvarchar(100) - PostgreSQL -> varchar(100) - Oracle -> nvarchar2(100) - Sqlite -> nvarchar(100) - --- - StringLength = -1 时,对应 DbType: - MySql -> text - SqlServer -> nvarchar(max) - PostgreSQL -> text - Oracle -> nvarchar2(4000) - Sqlite -> text - - - - - 执行 Insert 方法时使用此值 - 注意:如果是 getdate() 这种请可考虑使用 ServerTime,因为它对数据库间作了适配 - - - - - - - 自定义表达式函数解析 - 注意:请使用静态方法、或者在类上标记 - - - - - 自定义表达式函数解析的时候,指定参数不解析 SQL,而是直接传进来 - - - - - 数据库类型,可用于适配多种数据库环境 - - - - - 已解析的表达式中参数内容 - - - - - 表达式原始值 - - - - - 主对象的参数化对象,可重塑其属性 - - - - - 可附加参数化对象 - 注意:本属性只有 Where 的表达式解析才可用 - - - - - 将 c# 对象转换为 SQL - - - - - 返回表达式函数表示的 SQL 字符串 - - - - - 获取实体元数据 - - - - - - - 解析表达式 - - - - - - - 索引名 - - - - - 索引字段,为属性名以逗号分隔,如:Create_time ASC, Title ASC - - - - - 是否唯一 - - - - - 手工绑定 OneToMany、ManyToOne 导航关系 - - - - - 手工绑定 ManyToMany 导航关系 - - - - - 主键名 - - - - - 数据库表名 - - - - - 指定数据库旧的表名,修改实体命名时,同时设置此参数为修改之前的值,CodeFirst才可以正确修改数据库表;否则将视为【创建新表】 - - - - - 禁用 CodeFirst 同步结构迁移 - - - - - 数据库表名 - - - - - 指定数据库旧的表名,修改实体命名时,同时设置此参数为修改之前的值,CodeFirst才可以正确修改数据库表;否则将视为【创建新表】 - - - - - 禁用 CodeFirst 同步结构迁移 - - - - - 导航关系Fluent,与 NavigateAttribute 对应 - - - - 多对多关系的中间实体类型 - - - - - 设置实体的索引 - - 索引名 - 索引字段,为属性名以逗号分隔,如:Create_time ASC, Title ASC - 是否唯一 - - - - - 数据库表名 - - - - - 指定数据库旧的表名,修改实体命名时,同时设置此参数为修改之前的值,CodeFirst才可以正确修改数据库表;否则将视为【创建新表】 - - - - - 禁用 CodeFirst 同步结构迁移 - - - - - 导航关系Fluent,与 NavigateAttribute 对应 - - - - - 多对多关系的中间实体类型 - - - - - 设置实体的索引 - - 索引名 - 索引字段,为属性名以逗号分隔,如:Create_time ASC, Title ASC - 是否唯一 - - - - - 所属表 - - - - - 列名 - - - - - 映射到 C# 类型 - - - - - 数据库枚举类型int值 - - - - - 数据库类型,字符串,varchar - - - - - 数据库类型,字符串,varchar(255) - - - - - 最大长度 - - - - - 主键 - - - - - 自增标识 - - - - - 是否可DBNull - - - - - 备注 - - - - - 枚举类型标识 - - - - - 枚举项 - - - - - 唯一标识 - - - - - SqlServer下是Owner、PostgreSQL下是Schema、MySql下是数据库名 - - - - - 表名 - - - - - 表备注,SqlServer下是扩展属性 MS_Description - - - - - 表/视图 - - - - - 列 - - - - - 自增列 - - - - - 主键/组合 - - - - - 唯一键/组合 - - - - - 索引/组合 - - - - - 外键 - - - - - 类型标识 - - - - - 枚举项 - - - - - 通用的 Odbc 实现,只能做基本的 Crud 操作 - 不支持实体结构迁移、不支持分页(只能 Take 查询) - - 通用实现为了让用户自己适配更多的数据库,比如连接 mssql 2000、db2 等数据库 - 默认适配 SqlServer,可以继承后重新适配 FreeSql.Odbc.Default.OdbcAdapter,最好去看下代码 - - 适配新的 OdbcAdapter,请在 FreeSqlBuilder.Build 之后调用 IFreeSql.SetOdbcAdapter 方法设置 - - - - - 武汉达梦数据库有限公司 - - - - - Microsoft Office Access 是由微软发布的关联式数据库管理系统 - - - - - 获取实体的主键值,以 "*|_,[,_|*" 分割,当任意一个主键属性无值时,返回 null - - - - - 当Guid无值时,会生成有序的新值 - - - - - - 获取实体的主键值,多个主键返回数组 - - - - - - - - - 获取实体的属性值 - - - - - - - - - - 获取实体的所有数据,以 (1, 2, xxx) 的形式 - - - - - - - - - 使用新实体的值,复盖旧实体的值 - - - - - 使用新实体的主键值,复盖旧实体的主键值 - - - - - 设置实体中主键内的自增字段值(若存在) - - - - - - - - - 获取实体中主键内的自增字段值(若存在) - - - - - - - - 清除实体的主键值,将自增、Guid类型的主键值清除 - - - - - - - - 清除实体的主键值,将自增、Guid类型的主键值清除 - - - - - - - - 对比两个实体值,返回相同/或不相同的列名 - - - - - - - - - - - 设置实体中某属性的数值增加指定的值 - - - - - - - - - - 设置实体中某属性的值 - - - - - - - - - - 缓存执行 IUpdate.Set - - - - - - - - - 使用连接串(推荐) - - 数据库类型 - 数据库连接串 - 提供者的类型,一般不需要指定,如果一直提示“缺少 FreeSql 数据库实现包:FreeSql.Provider.MySql.dll,可前往 nuget 下载”的错误,说明反射获取不到类型,此时该参数可排上用场 - - - - - 使用从数据库,支持多个 - - 从数据库连接串 - - - - - 使用自定义数据库连接对象(放弃内置对象连接池技术) - - 数据库类型 - 数据库连接对象创建器 - 提供者的类型,一般不需要指定,如果一直提示“缺少 FreeSql 数据库实现包:FreeSql.Provider.MySql.dll,可前往 nuget 下载”的错误,说明反射获取不到类型,此时该参数可排上用场 - - - - - 【开发环境必备】自动同步实体结构到数据库,程序运行中检查实体表是否存在,然后创建或修改 - - true:运行时检查自动同步结构, false:不同步结构 - - - - - 将数据库的主键、自增、索引设置导入,适用 DbFirst 模式,无须在实体类型上设置 [Column(IsPrimary)] 或者 ConfigEntity。此功能目前可用于 mysql/sqlserver/postgresql/oracle。 - 本功能会影响 IFreeSql 首次访问的速度。 - 若使用 CodeFirst 创建索引后,又直接在数据库上建了索引,若无本功能下一次 CodeFirst 迁移时数据库上创建的索引将被删除 - - - - - - - 不使用命令参数化执行,针对 Insert/Update,也可临时使用 IInsert/IUpdate.NoneParameter() - - - - - - - 是否生成命令参数化执行,针对 lambda 表达式解析 - 注意:常量不会参数化,变量才会做参数化 - var id = 100; - fsql.Select<T>().Where(a => a.id == id) 会参数化 - fsql.Select<T>().Where(a => a.id == 100) 不会参数化 - - - - - - - 延时加载导航属性对象,导航属性需要声明 virtual - - - - - - - 监视数据库命令对象 - - 执行前 - 执行后,可监视执行性能 - - - - - 实体类名 -> 数据库表名,命名转换(类名、属性名都生效) - 优先级小于 [Table(Name = "xxx")]、[Column(Name = "xxx")] - - - - - - - 转小写同步结构 - - true:转小写, false:不转 - - - - - 转大写同步结构 - - true:转大写, false:不转 - - - - - 自动转换实体属性名称 Entity Property -> Db Filed - - *不会覆盖 [Column] 特性设置的Name - - - - - - - 指定事务对象 - - - - - - - 指定事务对象 - - - - - - - lambda表达式条件,仅支持实体基础成员(不包含导航对象) - 若想使用导航对象,请使用 ISelect.ToDelete() 方法 - - lambda表达式条件 - - - - - 原生sql语法条件,Where("id = ?id", new { id = 1 }) - - sql语法条件 - 参数 - - - - - 传入实体,将主键作为条件 - - 实体 - - - - - 传入实体集合,将主键作为条件 - - 实体集合 - - - - - 传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} - - 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 - 是否标识为NOT - - - - - 禁用全局过滤功能,不传参数时将禁用所有 - - 零个或多个过滤器名字 - - - - - 设置表名规则,可用于分库/分表,参数1:默认表名;返回值:新表名; - - - - - - - 动态Type,在使用 Delete<object> 后使用本方法,指定实体类型 - - - - - - - 返回即将执行的SQL语句 - - - - - - 执行SQL语句,返回影响的行数 - - - - - - 执行SQL语句,返回被删除的记录 - 注意:此方法只有 Postgresql/SqlServer 有效果 - - - - - - 指定事务对象 - - - - - - - 指定事务对象 - - - - - - - 追加准备插入的实体 - - 实体 - - - - - 追加准备插入的实体 - - 实体 - - - - - 追加准备插入的实体集合 - - 实体集合 - - - - - 只插入的列,InsertColumns(a => a.Name) | InsertColumns(a => new{a.Name,a.Time}) | InsertColumns(a => new[]{"name","time"}) - - lambda选择列 - - - - - 忽略的列,IgnoreColumns(a => a.Name) | IgnoreColumns(a => new{a.Name,a.Time}) | IgnoreColumns(a => new[]{"name","time"}) - - lambda选择列 - - - - - 指定可插入自增字段 - - - - - - 不使用参数化,可通过 IFreeSql.CodeFirst.IsNotCommandParameter 全局性设置 - - 是否不使用参数化 - - - - - 批量执行选项设置,一般不需要使用该方法 - 各数据库 values, parameters 限制不一样,默认设置: - MySql 5000 3000 - PostgreSQL 5000 3000 - SqlServer 1000 2100 - Oracle 500 999 - Sqlite 5000 999 - 若没有事务传入,内部(默认)会自动开启新事务,保证拆包执行的完整性。 - - 指定根据 values 数量拆分执行 - 指定根据 parameters 数量拆分执行 - 是否自动开启事务 - - - - - 设置表名规则,可用于分库/分表,参数1:默认表名;返回值:新表名; - - - - - - - 动态Type,在使用 Insert<object> 后使用本方法,指定实体类型 - - - - - - - 返回即将执行的SQL语句 - - - - - - 执行SQL语句,返回影响的行数 - - - - - - 执行SQL语句,返回自增值 - 注意:请检查实体类是否标记了 [Column(IsIdentity = true)] - - - - - - 执行SQL语句,返回插入后的记录 - 注意:此方法只有 Postgresql/SqlServer 有效果 - - - - - - 返回 DataTable 以便做 BulkCopy 数据做准备 - 此方法会处理: - 类型、表名、字段名映射 - IgnoreColumns、InsertColumns - - - - - - 自动产生 as1, as2, as3 .... 字段别名 - 这种方法可以最大程度防止多表,存在相同字段的问题 - - - - - 使用属性名作为字段别名 - - - - - 指定事务对象 - - - - - - - 指定连接对象 - - - - - - - 审核或跟踪 ToList 即将返回的数据 - - - - - - - 执行SQL查询,返回 DataTable - - - - - - 以字典的形式返回查询结果 - 注意:字典的特点会导致返回的数据无序 - - - - - - - - 执行SQL查询,返回 T1 实体所有字段的记录,记录不存在时返回 Count 为 0 的列表 - 注意: - 1、ToList(a => a) 可以返回 a 所有实体 - 2、ToList(a => new { a }) 这样也可以 - 3、ToList((a, b, c) => new { a, b, c }) 这样也可以 - 4、abc 怎么来的?请试试 fsql.Select<T1, T2, T3>() - - false: 返回 2级 LeftJoin/InnerJoin/RightJoin 对象;true: 返回所有 LeftJoin/InnerJoin/RightJoin 的导航数据 - - - - - 执行SQL查询,分块返回数据,可减少内存开销。比如读取10万条数据,每次返回100条处理。 - - 数据块的大小 - 处理数据块 - false: 返回 2级 LeftJoin/InnerJoin/RightJoin 对象;true: 返回所有 LeftJoin/InnerJoin/RightJoin 的导航数据 - - - - 执行SQL查询,返回 field 指定字段的记录,并以元组或基础类型(int,string,long)接收,记录不存在时返回 Count 为 0 的列表 - - - - - - - - 执行SQL查询,返回 T1 实体所有字段的第一条记录,记录不存在时返回 null - - - - - - 执行SQL查询,返回 T1 实体所有字段的第一条记录,记录不存在时返回 null - - - - - - 将查询转为删除对象,以便支持导航对象或其他查询功能删除数据,如下: - fsql.Select<T1>().Where(a => a.Options.xxx == 1).ToDelete().ExecuteAffrows() - 注意:此方法不是将数据查询到内存循环删除,上面的代码产生如下 SQL 执行: - DELETE FROM `T1` WHERE id in (select a.id from T1 a left join Options b on b.t1id = a.id where b.xxx = 1) - 复杂删除使用该方案的好处: - 1、删除前可预览测试数据,防止错误删除操作; - 2、支持更加复杂的删除操作(IDelete 默认只支持简单的操作); - - - - - - 将查询转为更新对象,以便支持导航对象或其他查询功能更新数据,如下: - fsql.Select<T1>().Where(a => a.Options.xxx == 1).ToUpdate().Set(a => a.Title, "111").ExecuteAffrows() - 注意:此方法不是将数据查询到内存循环更新,上面的代码产生如下 SQL 执行: - UPDATE `T1` SET Title = '111' WHERE id in (select a.id from T1 a left join Options b on b.t1id = a.id where b.xxx = 1) - 复杂更新使用该方案的好处: - 1、更新前可预览测试数据,防止错误更新操作; - 2、支持更加复杂的更新操作(IUpdate 默认只支持简单的操作); - - - - - - 设置表名规则,可用于分库/分表,参数1:实体类型;参数2:默认表名;返回值:新表名; - 设置多次,可查询分表后的多个子表记录,以 UNION ALL 形式执行。 - 如:select.AsTable((type, oldname) => "table_1").AsTable((type, oldname) => "table_2").AsTable((type, oldname) => "table_3").ToSql(a => a.Id); - select * from (SELECT a."Id" as1 FROM "table_1" a) ftb - UNION ALL select * from (SELECT a."Id" as1 FROM "table_2" a) ftb - UNION ALL select * from (SELECT a."Id" as1 FROM "table_3" a) ftb - 还可以这样:select.AsTable((a, b) => "(select * from tb_topic where clicks > 10)").Page(1, 10).ToList() - - - - - - - 设置别名规则,可用于拦截表别名,实现类似 sqlserver 的 with(nolock) 需求 - 如:select.AsAlias((_, old) => $"{old} with(lock)") - - - - - - - 动态Type,在使用 Select<object> 后使用本方法,指定实体类型 - - - - - - - 返回即将执行的SQL语句 - - 指定字段 - - - - - 执行SQL查询,是否有记录 - - - - - - 查询的记录数量 - - - - - - 查询的记录数量,以参数out形式返回 - - 返回的变量 - - - - - 指定从主库查询(默认查询从库) - - - - - - 左联查询,使用导航属性自动生成SQL - - 表达式 - - - - - 联接查询,使用导航属性自动生成SQL - - 表达式 - - - - - 右联查询,使用导航属性自动生成SQL - - 表达式 - - - - - 左联查询,指定关联的实体类型 - - 关联的实体类型 - 表达式 - - - - - 联接查询,指定关联的实体类型 - - 关联的实体类型 - 表达式 - - - - - 右联查询,指定关联的实体类型 - - 关联的实体类型 - 表达式 - - - - - 左联查询,使用原生sql语法,LeftJoin("type b on b.id = a.id and b.clicks > ?clicks", new { clicks = 1 }) - - sql语法条件 - 参数 - - - - - 联接查询,使用原生sql语法,InnerJoin("type b on b.id = a.id and b.clicks > ?clicks", new { clicks = 1 }) - - sql语法条件 - 参数 - - - - - 右联查询,使用原生sql语法,RightJoin("type b on b.id = a.id and b.clicks > ?clicks", new { clicks = 1 }) - - sql语法条件 - 参数 - - - - - 在 JOIN 位置插入 SQL 内容 - 如:.RawJoin("OUTER APPLY ( select id from t2 ) b") - - - - - - - 原生sql语法条件,Where("id = ?id", new { id = 1 }) - - sql语法条件 - 参数 - - - - - 原生sql语法条件,WhereIf(true, "id = ?id", new { id = 1 }) - - true 时生效 - sql语法条件 - 参数 - - - - - 禁用全局过滤功能,不传参数时将禁用所有 - - 零个或多个过滤器名字 - - - - - 排他更新锁 - 注意:务必在开启事务后使用该功能 - MySql: for update - SqlServer: With(UpdLock, RowLock, NoWait) - PostgreSQL: for update nowait - Oracle: for update nowait - Sqlite: 无效果 - 达梦: for update nowait - - noawait - - - - - 按原生sql语法分组,GroupBy("concat(name, ?cc)", new { cc = 1 }) - - sql语法 - 参数 - - - - - 按原生sql语法聚合条件过滤,Having("count(name) = ?cc", new { cc = 1 }) - - sql语法条件 - 参数 - - - - - 按原生sql语法排序,OrderBy("count(name) + ?cc desc", new { cc = 1 }) - - sql语法 - 参数 - - - - - 按原生sql语法排序,OrderBy(true, "count(name) + ?cc desc", new { cc = 1 }) - - true 时生效 - sql语法 - 参数 - - - - - 查询向后偏移行数 - - - - - - - 查询向后偏移行数 - - 行数 - - - - - 查询多少条数据 - - - - - - - 查询多少条数据 - - - - - - - 分页 - - 第几页 - 每页多少 - - - - - 查询数据前,去重 - - .Distinct().ToList(x => x.GroupName) 对指定字段去重 - - - .Distinct().ToList() 对整个查询去重 - - - - - - - 执行SQL查询,是否有记录 - - lambda表达式 - - - - - 执行SQL查询,返回 DataTable - - - - - - 执行SQL查询,返回指定字段的记录,记录不存在时返回 Count 为 0 的列表 - - 返回类型 - 选择列 - - - - - 执行SQL查询,返回 TDto 映射的字段,记录不存在时返回 Count 为 0 的列表 - - - - - - - 执行SQL查询,返回指定字段的记录的第一条记录,记录不存在时返回 TReturn 默认值 - - 返回类型 - 选择列 - - - - - 执行SQL查询,返回 TDto 映射的字段,记录不存在时返回 Dto 默认值 - - - - - - - 执行SQL查询,返回指定字段的记录的第一条记录,记录不存在时返回 TReturn 默认值 - - 返回类型 - 选择列 - - - - - 执行SQL查询,返回 TDto 映射的字段,记录不存在时返回 Dto 默认值 - - - - - - - 返回即将执行的SQL语句 - - 返回类型 - 选择列 - 字段别名 - - - - - 执行SQL查询,返回指定字段的聚合结果 - - - - - - - - 求和 - - 返回类型 - 列 - - - - - 最小值 - - 返回类型 - 列 - - - - - 最大值 - - 返回类型 - 列 - - - - - 平均值 - - 返回类型 - 列 - - - - - 指定别名 - - 别名 - - - - - 多表查询 - - - - - - - - 多表查询 - - - - - - - - - 多表查询 - - - - - - - - - - 多表查询 - - - - - - - - - - - 多表查询 - - - - - - - - - - - - 多表查询 - - - - - - - - - - - - - 多表查询 - - - - - - - - - - - - - - 多表查询 - - - - - - - - - - - - - - - 多表查询 - - - - - - - - - - - - - - - - 查询条件,Where(a => a.Id > 10),支持导航对象查询,Where(a => a.Author.Email == "2881099@qq.com") - - lambda表达式 - - - - - 查询条件,Where(true, a => a.Id > 10),支导航对象查询,Where(true, a => a.Author.Email == "2881099@qq.com") - - true 时生效 - lambda表达式 - - - - - 多表条件查询 - - - lambda表达式 - - - - - 多表条件查询 - - - lambda表达式 - - - - - 多表条件查询 - - - - lambda表达式 - - - - - 多表条件查询 - - - - - lambda表达式 - - - - - 多表条件查询 - - - - - lambda表达式 - - - - - 传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} - - 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 - 是否标识为NOT - - - - - 多表查询时,该方法标记后,表达式条件将对所有表进行附加 - - 例如:软删除、租户,每个表都给条件,挺麻烦的 - - fsql.Select<T1>().LeftJoin<T2>(...).Where<T2>((t1, t2 => t1.IsDeleted == false && t2.IsDeleted == false) - - 修改:fsql.Select<T1>().LeftJoin<T2>(...).WhereCascade(t1 => t1.IsDeleted == false) - - 当其中的实体可附加表达式才会进行,表越多时收益越大 - - - - - - - 按选择的列分组,GroupBy(a => a.Name) | GroupBy(a => new{a.Name,a.Time}) - - - - - - - 按列排序,OrderBy(a => a.Time) - - - - - - - - 按列排序,OrderBy(true, a => a.Time) - - - true 时生效 - - - - - - 按列倒向排序,OrderByDescending(a => a.Time) - - 列 - - - - - 按列倒向排序,OrderByDescending(true, a => a.Time) - - true 时生效 - 列 - - - - - 贪婪加载导航属性,如果查询中已经使用了 a.Parent.Parent 类似表达式,则可以无需此操作 - - - 选择一个导航属性 - - - - - 贪婪加载集合的导航属性,其实是分两次查询,ToList 后进行了数据重装 - 文档:https://github.com/2881099/FreeSql/wiki/%e8%b4%aa%e5%a9%aa%e5%8a%a0%e8%bd%bd#%E5%AF%BC%E8%88%AA%E5%B1%9E%E6%80%A7-onetomanymanytomany - - - 选择一个集合的导航属性,如: .IncludeMany(a => a.Tags) - 可以 .Where 设置临时的关系映射,如: .IncludeMany(a => a.Tags.Where(tag => tag.TypeId == a.Id)) - 可以 .Take(5) 每个子集合只取5条,如: .IncludeMany(a => a.Tags.Take(5)) - 可以 .Select 设置只查询部分字段,如: (a => new TNavigate { Title = a.Title }) - - 即能 ThenInclude,还可以二次过滤(这个 EFCore 做不到?) - - - - - 实现 select .. from ( select ... from t ) a 这样的功能 - 使用 AsTable 方法也可以达到效果 - - SQL语句 - - - - - 查询条件,Where(a => a.Id > 10),支持导航对象查询,Where(a => a.Author.Email == "2881099@qq.com") - - lambda表达式 - - - - - 查询条件,Where(true, a => a.Id > 10),支导航对象查询,Where(true, a => a.Author.Email == "2881099@qq.com") - - true 时生效 - lambda表达式 - - - - - 按列排序,OrderBy(a => a.Time) - - - - - - - - 按列倒向排序,OrderByDescending(a => a.Time) - - 列 - - - - - 按聚合条件过滤,Where(a => a.Count() > 10) - - lambda表达式 - - - - - 按列排序,OrderBy(a => a.Time) - - - - - - - - 按列倒向排序,OrderByDescending(a => a.Time) - - 列 - - - - - 执行SQL查询,返回指定字段的记录,记录不存在时返回 Count 为 0 的列表 - - 返回类型 - 选择列 - - - - - 【linq to sql】专用方法,不建议直接使用 - - - - - 返回即将执行的SQL语句 - - 返回类型 - 选择列 - - - - - 返回即将执行的SQL语句 - - 指定字段 - - - - - 查询向后偏移行数 - - - - - - - 查询向后偏移行数 - - 行数 - - - - - 查询多少条数据 - - - - - - - 查询多少条数据 - - - - - - - 分页 - - 第几页 - 每页多少 - - - - - 查询的记录数量 - - - - - - 查询的记录数量,以参数out形式返回 - - 返回的变量 - - - - - 分组的数据 - - - - - 记录总数 - - - - - - 求和 - - - - - - - - 平均值 - - - - - - - - 最大值 - - - - - - - - 最小值 - - - - - - - 所有元素 - - - - - 指定事务对象 - - - - - - - 指定事务对象 - - - - - - - 不使用参数化,可通过 IFreeSql.CodeFirst.IsNotCommandParameter 全局性设置 - - 是否不使用参数化 - - - - - 批量执行选项设置,一般不需要使用该方法 - 各数据库 rows, parameters 限制不一样,默认设置: - MySql 500 3000 - PostgreSQL 500 3000 - SqlServer 500 2100 - Oracle 200 999 - Sqlite 200 999 - 若没有事务传入,内部(默认)会自动开启新事务,保证拆包执行的完整性。 - - 指定根据 rows 数量拆分执行 - 指定根据 parameters 数量拆分执行 - 是否自动开启事务 - - - - - 更新数据,设置更新的实体 - - 实体 - - - - - 更新数据,设置更新的实体集合 - - 实体集合 - - - - - 忽略的列,IgnoreColumns(a => a.Name) | IgnoreColumns(a => new{a.Name,a.Time}) | IgnoreColumns(a => new[]{"name","time"}) - - lambda选择列 - - - - - 忽略的列 - - 属性名,或者字段名 - - - - - 指定的列,UpdateColumns(a => a.Name) | UpdateColumns(a => new{a.Name,a.Time}) | UpdateColumns(a => new[]{"name","time"}) - - lambda选择列 - - - - - 指定的列 - - 属性名,或者字段名 - - - - - 设置列的新值,Set(a => a.Name, "newvalue") - - - lambda选择列 - 新值 - - - - - 设置列的的新值为基础上增加,格式:Set(a => a.Clicks + 1) 相当于 clicks=clicks+1 - - 指定更新,格式:Set(a => new T { Clicks = a.Clicks + 1, Time = DateTime.Now }) 相当于 set clicks=clicks+1,time='2019-06-19....' - - - - - - - - 设置值,自定义SQL语法,SetRaw("title = ?title", new { title = "newtitle" }) - - sql语法 - 参数 - - - - - 设置更新的列 - - SetDto(new { title = "xxx", clicks = 2 }) - - SetDto(new Dictionary<string, object> { ["title"] = "xxx", ["clicks"] = 2 }) - - dto 或 Dictionary<string, object> - - - - - lambda表达式条件,仅支持实体基础成员(不包含导航对象) - 若想使用导航对象,请使用 ISelect.ToUpdate() 方法 - - lambda表达式条件 - - - - - 原生sql语法条件,Where("id = ?id", new { id = 1 }) - - sql语法条件 - 参数 - - - - - 传入实体,将主键作为条件 - - 实体 - - - - - 传入实体集合,将主键作为条件 - - 实体集合 - - - - - 传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} - - 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 - 是否标识为NOT - - - - - 禁用全局过滤功能,不传参数时将禁用所有 - - 零个或多个过滤器名字 - - - - - 设置表名规则,可用于分库/分表,参数1:默认表名;返回值:新表名; - - - - - - - 动态Type,在使用 Update<object> 后使用本方法,指定实体类型 - - - - - - - 返回即将执行的SQL语句 - - - - - - 执行SQL语句,返回影响的行数 - - - - - - 执行SQL语句,返回更新后的记录 - 注意:此方法只有 Postgresql/SqlServer 有效果 - - - - - - 主库连接池 - - - - - 从库连接池 - - - - - 数据库类型 - - - - - UseConnectionString 时候的值 - - - - - UseSalve 时候的值 - - - - - 唯一标识 - - - - - 开启事务(不支持异步),60秒未执行完成(可能)被其他线程事务自动提交 - - 事务体 () => {} - - - - 开启事务(不支持异步) - - 超时,未执行完成(可能)被其他线程事务自动提交 - 事务体 () => {} - - - - 开启事务(不支持异步) - - - 事务体 () => {} - 超时,未执行完成(可能)被其他线程事务自动提交 - - - - 当前线程的事务 - - - - - 查询,若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】 - - - - - - - - - 查询,ExecuteReader(dr => {}, "select * from user where age > ?age", new { age = 25 }) - - - - - - - 查询 - - - - - - - 查询,ExecuteArray("select * from user where age > ?age", new { age = 25 }) - - - - - - - - 查询 - - - - - - - 查询,ExecuteDataSet("select * from user where age > ?age; select 2", new { age = 25 }) - - - - - - - - 查询 - - - - - - - 查询,ExecuteDataTable("select * from user where age > ?age", new { age = 25 }) - - - - - - - - 在【主库】执行 - - - - - - - - 在【主库】执行,ExecuteNonQuery("delete from user where age > ?age", new { age = 25 }) - - - - - - - - 在【主库】执行 - - - - - - - - 在【主库】执行,ExecuteScalar("select 1 from user where age > ?age", new { age = 25 }) - - - - - - - - 执行SQL返回对象集合,Query<User>("select * from user where age > ?age", new SqlParameter { ParameterName = "age", Value = 25 }) - - - - - - - - - - 执行SQL返回对象集合,Query<User>("select * from user where age > ?age", new { age = 25 }) - - - - - - - - - 执行SQL返回对象集合,Query<User>("select * from user where age > ?age; select * from address", new SqlParameter { ParameterName = "age", Value = 25 }) - - - - - - - - - - 执行SQL返回对象集合,Query<User>("select * from user where age > ?age; select * from address", new { age = 25 }) - - - - - - - - - 可自定义解析表达式 - - - - - 自定义实体的配置,方便和多个 ORM 共同使用 - - - - - 自定义实体的属性配置,方便和多个 ORM 共同使用 - - - - - 增删查改,执行命令之前触发 - - - - - 增删查改,执行命令完成后触发 - - - - - CodeFirst迁移,执行之前触发 - - - - - CodeFirst迁移,执行完成触发 - - - - - Insert/Update自动值处理 - - - - - 监视数据库命令对象(执行前,调试) - - - - - 监视数据库命令对象(执行后,用于监视执行性能) - - - - - 跟踪开始 - - - - - 跟踪结束 - - - - - 内置解析功能,可辅助您进行解析 - - - - - 需要您解析的表达式 - - - - - 解析后的内容 - - - - - 实体类型 - - - - - 实体配置 - - - - - 索引配置 - - - - - 实体类型 - - - - - 实体的属性 - - - - - 实体的属性配置 - - - - - 标识符,可将 CurdBefore 与 CurdAfter 进行匹配 - - - - - 操作类型 - - - - - 实体类型 - - - - - 实体类型的元数据 - - - - - 执行的 SQL - - - - - 参数化命令 - - - - - 发生的错误 - - - - - 执行SQL命令,返回的结果 - - - - - 耗时(单位:Ticks) - - - - - 耗时(单位:毫秒) - - - - - 标识符,可将 SyncStructureBeforeEventArgs 与 SyncStructureAfterEventArgs 进行匹配 - - - - - 实体类型 - - - - - 执行的 SQL - - - - - 发生的错误 - - - - - 耗时(单位:Ticks) - - - - - 耗时(单位:毫秒) - - - - - 类型 - - - - - 属性列的元数据 - - - - - 反射的属性信息 - - - - - 获取实体的属性值,也可以设置实体的属性新值 - - - - - 标识符,可将 CommandBefore 与 CommandAfter 进行匹配 - - - - - 发生的错误 - - - - - 执行SQL命令,返回的结果 - - - - - 耗时(单位:Ticks) - - - - - 耗时(单位:毫秒) - - - - - 标识符,可将 TraceBeforeEventArgs 与 TraceAfterEventArgs 进行匹配 - - - - - 备注 - - - - - 发生的错误 - - - - - 耗时(单位:Ticks) - - - - - 耗时(单位:毫秒) - - - - - 【开发环境必备】自动同步实体结构到数据库,程序运行中检查实体表是否存在,然后创建或修改 - - - - - 转小写同步结构,适用 PostgreSQL - - - - - 转大写同步结构,适用 Oracle/达梦 - - - - - 将数据库的主键、自增、索引设置导入,适用 DbFirst 模式,无须在实体类型上设置 [Column(IsPrimary)] 或者 ConfigEntity。此功能目前可用于 mysql/sqlserver/postgresql/oracle。 - 本功能会影响 IFreeSql 首次访问的速度。 - 若使用 CodeFirst 创建索引后,又直接在数据库上建了索引,若无本功能下一次 CodeFirst 迁移时数据库上创建的索引将被删除 - - - - - 不使用命令参数化执行,针对 Insert/Update - - - - - 是否生成命令参数化执行,针对 lambda 表达式解析 - 注意:常量不会参数化,变量才会做参数化 - var id = 100; - fsql.Select<T>().Where(a => a.id == id) 会参数化 - fsql.Select<T>().Where(a => a.id == 100) 不会参数化 - - - - - 延时加载导航属性对象,导航属性需要声明 virtual - - - - - 将实体类型与数据库对比,返回DDL语句 - - - - - - - 将实体类型集合与数据库对比,返回DDL语句 - - 实体类型 - - - - - 将实体类型与数据库对比,返回DDL语句(指定表名) - - 实体类型 - 指定表名对比 - - - - - 同步实体类型到数据库 - - - - - - 同步实体类型集合到数据库 - - - - - - 同步实体类型到数据库(指定表名) - - 实体类型 - 指定表名对比 - - - - 根据 System.Type 获取数据库信息 - - - - - - - 在外部配置实体的特性 - - - - - - - - 在外部配置实体的特性 - - - - - - - - 获取在外部配置实体的特性 - - - 未使用ConfigEntity配置时,返回null - - - - 获取实体类核心配置 - - - - - - - 获取所有数据库 - - - - - - 获取指定数据库的表信息,包括表、列详情、主键、唯一键、索引、外键、备注 - - - - - - - 获取数据库枚举类型int值 - - - - - - - 获取c#转换,(int)、(long) - - - - - - - 获取c#值 - - - - - - - 获取c#类型,int、long - - - - - - - 获取c#类型对象 - - - - - - - 获取ado.net读取方法, GetBoolean、GetInt64 - - - - - - - 序列化 - - - - - - - 反序列化 - - - - - - - 获取数据库枚举类型,适用 PostgreSQL - - - - - - - AsType, Ctor, ClearData 三处地方需要重新加载 - - - - - AsType, Ctor, ClearData 三处地方需要重新加载 - - - - - 通过属性的注释文本,通过 xml 读取 - - - Dict:key=属性名,value=注释 - - - - 创建一个过滤器 - - - 名字 - 表达式 - - - - - 中间表,多对多 - - - - - 是否可用 - - - - - 不可用错误 - - - - - 不可用时间 - - - - - 将对象池设置为不可用,后续 Get/GetAsync 均会报错,同时启动后台定时检查服务恢复可用 - - - 由【可用】变成【不可用】时返回true,否则返回false - - - - 统计对象池中的对象 - - - - - 统计对象池中的对象(完整) - - - - - 获取资源 - - 超时 - - - - - 使用完毕后,归还资源 - - 对象 - 是否重新创建 - - - - 名称 - - - - - 池容量 - - - - - 默认获取超时设置 - - - - - 空闲时间,获取时若超出,则重新创建 - - - - - 异步获取排队队列大小,小于等于0不生效 - - - - - 获取超时后,是否抛出异常 - - - - - 监听 AppDomain.CurrentDomain.ProcessExit/Console.CancelKeyPress 事件自动释放 - - - - - 后台定时检查可用性间隔秒数 - - - - - 对象池的对象被创建时 - - 返回被创建的对象 - - - - 销毁对象 - - 资源对象 - - - - 从对象池获取对象超时的时候触发,通过该方法统计 - - - - - 从对象池获取对象成功的时候触发,通过该方法统计或初始化对象 - - - - - - - 反序列化 - - - - - - - 获取数据库枚举类型,适用 PostgreSQL - - - - - - - AsType, Ctor, ClearData 三处地方需要重新加载 - - - - - AsType, Ctor, ClearData 三处地方需要重新加载 - - - - - 通过属性的注释文本,通过 xml 读取 - - - Dict:key=属性名,value=注释 - - - - 创建一个过滤器 - - - 名字 - 表达式 - - - - - 中间表,多对多 - - - - - 是否可用 - - - - - 不可用错误 - - - - - 不可用时间 - - - - - 将对象池设置为不可用,后续 Get/GetAsync 均会报错,同时启动后台定时检查服务恢复可用 - - - 由【可用】变成【不可用】时返回true,否则返回false - - - - 统计对象池中的对象 - - - - - 统计对象池中的对象(完整) - - - - - 获取资源 - - 超时 - - - - - 获取资源 - - - - - - 使用完毕后,归还资源 - < - - - - - 不进行任何处理 - - - - - 将帕斯卡命名字符串转换为下划线分隔字符串 - - BigApple -> Big_Apple - - - - - 将帕斯卡命名字符串转换为下划线分隔字符串,且转换为全大写 - - BigApple -> BIG_APPLE - - - - - 将帕斯卡命名字符串转换为下划线分隔字符串,且转换为全小写 - - BigApple -> big_apple - - - - - 将字符串转换为大写 - - BigApple -> BIGAPPLE - - - - - 将字符串转换为小写 - - BigApple -> bigapple - - - - - 不进行任何处理 - - - - - 将帕斯卡命名字符串转换为下划线分隔字符串 - - BigApple -> Big_Apple - - - - - 将帕斯卡命名字符串转换为下划线分隔字符串,且转换为全大写 - - BigApple -> BIG_APPLE - - - - - 将帕斯卡命名字符串转换为下划线分隔字符串,且转换为全小写 - - BigApple -> big_apple - - - - - 将字符串转换为大写 - - BigApple -> BIGAPPLE - - - - - 将字符串转换为小写 - - BigApple -> bigapple - - - - - C#: that >= between && that <= and - SQL: that BETWEEN between AND and - - - - - - - - - 注意:这个方法和 Between 有细微区别 - C#: that >= start && that < end - SQL: that >= start and that < end - - - Object`1.Pool"> - - 所属对象池 - - - - - 在对象池中的唯一标识 - - - - - 资源对象 - - - - - 被获取的总次数 - - - - 最后获取时的时间 - - - - 最后归还时的时间 - - - - - 创建时间 - - - - - 最后获取时的线程id - - - - - 最后归还时的线程id - - - - - 重置 Value 值 - - - - - 对象池管理类 - - 对象类型 - - - - 后台定时检查可用性 - - - - - - 创建对象池 - - 池大小 - 池内对象的创建委托 - 获取池内对象成功后,进行使用前操作 - - - - 创建对象池 - - 策略 - - - - 获取可用资源,或创建资源 - - - - - - 不进行任何处理 - - - - - 将帕斯卡命名字符串转换为下划线分隔字符串 - - BigApple -> Big_Apple - - - - - 将帕斯卡命名字符串转换为下划线分隔字符串,且转换为全大写 - - BigApple -> BIG_APPLE - - - - - 将帕斯卡命名字符串转换为下划线分隔字符串,且转换为全小写 - - BigApple -> big_apple - - - - - 将字符串转换为大写 - - BigApple -> BIGAPPLE - - - - - 将字符串转换为小写 - - BigApple -> bigapple - - - - - 不进行任何处理 - - - - - 将帕斯卡命名字符串转换为下划线分隔字符串 - - BigApple -> Big_Apple - - - - - 将帕斯卡命名字符串转换为下划线分隔字符串,且转换为全大写 - - BigApple -> BIG_APPLE - - - - - 将帕斯卡命名字符串转换为下划线分隔字符串,且转换为全小写 - - BigApple -> big_apple - - - - - 将字符串转换为大写 - - BigApple -> BIGAPPLE - - - - - 将字符串转换为小写 - - BigApple -> bigapple - - - - - C#: that >= between && that <= and - SQL: that BETWEEN between AND and - - - - - - - - - 注意:这个方法和 Between 有细微区别 - C#: that >= start && that < end - SQL: that >= start and that < end - - - - - - - - - 获取 Type 的原始 c# 文本表示 - - - - - - - 测量两个经纬度的距离,返回单位:米 - - 经纬坐标1 - 经纬坐标2 - 返回距离(单位:米) - - - - 将 IEnumable<T> 转成 ISelect<T>,以便使用 FreeSql 的查询功能。此方法用于 Lambad 表达式中,快速进行集合导航的查询。 - - - - - - - - 多表查询 - - - - - - 多表查询 - - - - - - 多表查询 - - - - - - 多表查询 - - - - - - 多表查询 - - - - - - 多表查询 - - - - - - 多表查询 - - - - - - 多表查询 - - - - - - 多表查询 - - - - - - 本方法实现从已知的内存 List 数据,进行和 ISelect.IncludeMany 相同功能的贪婪加载 - 示例:new List<Song>(new[] { song1, song2, song3 }).IncludeMany(g.sqlite, a => a.Tags); - 文档:https://github.com/2881099/FreeSql/wiki/%e8%b4%aa%e5%a9%aa%e5%8a%a0%e8%bd%bd#%E5%AF%BC%E8%88%AA%E5%B1%9E%E6%80%A7-onetomanymanytomany - - - 选择一个集合的导航属性,如: .IncludeMany(a => a.Tags) - 可以 .Where 设置临时的关系映射,如: .IncludeMany(a => a.Tags.Where(tag => tag.TypeId == a.Id)) - 可以 .Take(5) 每个子集合只取5条,如: .IncludeMany(a => a.Tags.Take(5)) - 可以 .Select 设置只查询部分字段,如: (a => new TNavigate { Title = a.Title }) - - 即能 ThenInclude,还可以二次过滤(这个 EFCore 做不到?) - - - - - 查询数据,加工为树型 List 返回 - 注意:实体需要配置父子导航属性 - - - - - - - - 使用 and 拼接两个 lambda 表达式 - - - - - - 使用 and 拼接两个 lambda 表达式 - - - true 时生效 - - - - - - 使用 or 拼接两个 lambda 表达式 - - - - - - 使用 or 拼接两个 lambda 表达式 - - - true 时生效 - - - - - - 将 lambda 表达式取反 - - - true 时生效 - - - - - 使用 and 拼接两个 lambda 表达式 - - - - - - 使用 and 拼接两个 lambda 表达式 - - - true 时生效 - - - - - - 使用 or 拼接两个 lambda 表达式 - - - - - - 使用 or 拼接两个 lambda 表达式 - - - true 时生效 - - - - - - 将 lambda 表达式取反 - - - - - 插入数据 - - - - - - - 插入数据,传入实体 - - - - - - - - 插入数据,传入实体数组 - - - - - - - - 插入数据,传入实体集合 - - - - - - - - 插入数据,传入实体集合 - - - - - - - - 修改数据 - - - - - - - 修改数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} - - - 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 - - - - - 查询数据 - - - - - - - 查询数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} - - - 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 - - - - - 删除数据 - - - - - - - 删除数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} - - - 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 - - - - - 开启事务(不支持异步),60秒未执行完成(可能)被其他线程事务自动提交 - - 事务体 () => {} - - - - - true 时生效 - - - - - - 将 lambda 表达式取反 - - - true 时生效 - - - - - 使用 and 拼接两个 lambda 表达式 - - - - - - 使用 and 拼接两个 lambda 表达式 - - - true 时生效 - - - - - - 使用 or 拼接两个 lambda 表达式 - - - - - - 使用 or 拼接两个 lambda 表达式 - - - true 时生效 - - - - - - 将 lambda 表达式取反 - - - true 时生效 - - - - - 生成类似Mongodb的ObjectId有序、不重复Guid - - - - - - 插入数据 - - - - - - - 插入数据,传入实体 - - - - - - - - 插入数据,传入实体数组 - - - - - - - - 插入数据,传入实体集合 - - - - - - - - 插入数据,传入实体集合 - - - - - - - - 修改数据 - - - - - - - 修改数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} - - - 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 - - - - - 查询数据 - - - - - - - 查询数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} - - - 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 - - - - - 删除数据 - - - - - - - 删除数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} - - - 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 - - - - - 开启事务(不支持异步),60秒未执行完成(可能)被其他线程事务自动提交 - - 事务体 () => {} - - - - 开启事务(不支持异步) - - 超时,未执行完成(可能)被其他线程事务自动提交 - 事务体 () => {} - - - - 开启事务(不支持异步) - - - 事务体 () => {} - 超时,未执行完成(可能)被其他线程事务自动提交 - - - - 数据库访问对象 - - - - - 所有拦截方法都在这里 - - - - - CodeFirst 模式开发相关方法 - - - - - DbFirst 模式开发相关方法 - - - - - 全局过滤设置,可默认附加为 Select/Update/Delete 条件 - - - - + + + + FreeSql + + + + + 数据库列名 + + + + + 指定数据库旧的列名,修改实体属性命名时,同时设置此参数为修改之前的值,CodeFirst才可以正确修改数据库字段;否则将视为【新增字段】 + + + + + 数据库类型,如: varchar(255) + 字符串长度,可使用特性 [MaxLength(255)] + + + + + 主键 + + + + + 自增标识 + + + + + 是否可DBNull + + + + + 忽略此列,不迁移、不插入 + + + + + 设置行锁(乐观锁)版本号,每次更新累加版本号,若更新整个实体时会附带当前的版本号判断(修改失败时抛出异常) + + + + + 类型映射,除了可做基本的类型映射外,特别介绍的功能: + 1、将 enum 属性映射成 typeof(string) + 2、将 对象 属性映射成 typeof(string),请安装扩展包 FreeSql.Extensions.JsonMap + + + + + 创建表时字段的位置(场景:实体继承后设置字段顺序),规则如下: + + >0时排前面,1,2,3... + + =0时排中间(默认) + + <0时排后面,...-3,-2,-1 + + + + + 该字段是否可以插入,默认值true,指定为false插入时该字段会被忽略 + + + + + 该字段是否可以更新,默认值true,指定为false更新时该字段会被忽略 + + + + + 标记属性为数据库服务器时间(utc/local),在插入的时候使用类似 getdate() 执行 + + + + + 设置长度,针对 string 类型避免 DbType 的繁琐设置 + 提示:也可以使用 [MaxLength(100)] + --- + StringLength = 100 时,对应 DbType: + MySql -> varchar(100) + SqlServer -> nvarchar(100) + PostgreSQL -> varchar(100) + Oracle -> nvarchar2(100) + Sqlite -> nvarchar(100) + --- + StringLength = -1 时,对应 DbType: + MySql -> text + SqlServer -> nvarchar(max) + PostgreSQL -> text + Oracle -> nvarchar2(4000) + Sqlite -> text + + + + + 执行 Insert 方法时使用此值 + 注意:如果是 getdate() 这种请可考虑使用 ServerTime,因为它对数据库间作了适配 + + + + + 数据库列名 + + + + + 指定数据库旧的列名,修改实体属性命名时,同时设置此参数为修改之前的值,CodeFirst才可以正确修改数据库字段;否则将视为【新增字段】 + + + + + 数据库类型,如: varchar(255) + + + + + 主键 + + + + + 自增标识 + + + + + 是否可DBNull + + + + + 忽略此列,不迁移、不插入 + + + + + 乐观锁 + + + + + 类型映射,比如:可将 enum 属性映射成 typeof(string) + + + + + + + 创建表时字段位置,规则如下: + + >0时排前面 + + =0时排中间(默认) + + <0时排后面 + + + + + + + 该字段是否可以插入,默认值true,指定为false插入时该字段会被忽略 + + + + + + + 该字段是否可以更新,默认值true,指定为false更新时该字段会被忽略 + + + + + + + 标记属性为数据库服务器时间(utc/local),在插入的时候使用类似 getdate() 执行 + + + + + + + 设置长度,针对 string 类型避免 DbType 的繁琐设置 + --- + StringLength = 100 时,对应 DbType: + MySql -> varchar(100) + SqlServer -> nvarchar(100) + PostgreSQL -> varchar(100) + Oracle -> nvarchar2(100) + Sqlite -> nvarchar(100) + --- + StringLength = -1 时,对应 DbType: + MySql -> text + SqlServer -> nvarchar(max) + PostgreSQL -> text + Oracle -> nvarchar2(4000) + Sqlite -> text + + + + + 执行 Insert 方法时使用此值 + 注意:如果是 getdate() 这种请可考虑使用 ServerTime,因为它对数据库间作了适配 + + + + + + + 自定义表达式函数解析 + 注意:请使用静态方法、或者在类上标记 + + + + + 自定义表达式函数解析的时候,指定参数不解析 SQL,而是直接传进来 + + + + + 数据库类型,可用于适配多种数据库环境 + + + + + 已解析的表达式中参数内容 + + + + + 表达式原始值 + + + + + 主对象的参数化对象,可重塑其属性 + + + + + 可附加参数化对象 + 注意:本属性只有 Where 的表达式解析才可用 + + + + + 将 c# 对象转换为 SQL + + + + + 返回表达式函数表示的 SQL 字符串 + + + + + 获取实体元数据 + + + + + + + 解析表达式 + + + + + + + 索引名 + + + + + 索引字段,为属性名以逗号分隔,如:Create_time ASC, Title ASC + + + + + 是否唯一 + + + + + 手工绑定 OneToMany、ManyToOne 导航关系 + + + + + 手工绑定 ManyToMany 导航关系 + + + + + 主键名 + + + + + 数据库表名 + + + + + 指定数据库旧的表名,修改实体命名时,同时设置此参数为修改之前的值,CodeFirst才可以正确修改数据库表;否则将视为【创建新表】 + + + + + 禁用 CodeFirst 同步结构迁移 + + + + + 数据库表名 + + + + + 指定数据库旧的表名,修改实体命名时,同时设置此参数为修改之前的值,CodeFirst才可以正确修改数据库表;否则将视为【创建新表】 + + + + + 禁用 CodeFirst 同步结构迁移 + + + + + 导航关系Fluent,与 NavigateAttribute 对应 + + + + 多对多关系的中间实体类型 + + + + + 设置实体的索引 + + 索引名 + 索引字段,为属性名以逗号分隔,如:Create_time ASC, Title ASC + 是否唯一 + + + + + 数据库表名 + + + + + 指定数据库旧的表名,修改实体命名时,同时设置此参数为修改之前的值,CodeFirst才可以正确修改数据库表;否则将视为【创建新表】 + + + + + 禁用 CodeFirst 同步结构迁移 + + + + + 导航关系Fluent,与 NavigateAttribute 对应 + + + + + 多对多关系的中间实体类型 + + + + + 设置实体的索引 + + 索引名 + 索引字段,为属性名以逗号分隔,如:Create_time ASC, Title ASC + 是否唯一 + + + + + 所属表 + + + + + 列名 + + + + + 映射到 C# 类型 + + + + + 数据库枚举类型int值 + + + + + 数据库类型,字符串,varchar + + + + + 数据库类型,字符串,varchar(255) + + + + + 最大长度 + + + + + 主键 + + + + + 自增标识 + + + + + 是否可DBNull + + + + + 备注 + + + + + 枚举类型标识 + + + + + 枚举项 + + + + + 唯一标识 + + + + + SqlServer下是Owner、PostgreSQL下是Schema、MySql下是数据库名 + + + + + 表名 + + + + + 表备注,SqlServer下是扩展属性 MS_Description + + + + + 表/视图 + + + + + 列 + + + + + 自增列 + + + + + 主键/组合 + + + + + 唯一键/组合 + + + + + 索引/组合 + + + + + 外键 + + + + + 类型标识 + + + + + 枚举项 + + + + + 通用的 Odbc 实现,只能做基本的 Crud 操作 + 不支持实体结构迁移、不支持分页(只能 Take 查询) + + 通用实现为了让用户自己适配更多的数据库,比如连接 mssql 2000、db2 等数据库 + 默认适配 SqlServer,可以继承后重新适配 FreeSql.Odbc.Default.OdbcAdapter,最好去看下代码 + + 适配新的 OdbcAdapter,请在 FreeSqlBuilder.Build 之后调用 IFreeSql.SetOdbcAdapter 方法设置 + + + + + 武汉达梦数据库有限公司 + + + + + Microsoft Office Access 是由微软发布的关联式数据库管理系统 + + + + + 获取实体的主键值,以 "*|_,[,_|*" 分割,当任意一个主键属性无值时,返回 null + + + + + 当Guid无值时,会生成有序的新值 + + + + + + 获取实体的主键值,多个主键返回数组 + + + + + + + + + 获取实体的属性值 + + + + + + + + + + 获取实体的所有数据,以 (1, 2, xxx) 的形式 + + + + + + + + + 使用新实体的值,复盖旧实体的值 + + + + + 使用新实体的主键值,复盖旧实体的主键值 + + + + + 设置实体中主键内的自增字段值(若存在) + + + + + + + + + 获取实体中主键内的自增字段值(若存在) + + + + + + + + 清除实体的主键值,将自增、Guid类型的主键值清除 + + + + + + + + 清除实体的主键值,将自增、Guid类型的主键值清除 + + + + + + + + 对比两个实体值,返回相同/或不相同的列名 + + + + + + + + + + + 设置实体中某属性的数值增加指定的值 + + + + + + + + + + 设置实体中某属性的值 + + + + + + + + + + 缓存执行 IUpdate.Set + + + + + + + + + 使用连接串(推荐) + + 数据库类型 + 数据库连接串 + 提供者的类型,一般不需要指定,如果一直提示“缺少 FreeSql 数据库实现包:FreeSql.Provider.MySql.dll,可前往 nuget 下载”的错误,说明反射获取不到类型,此时该参数可排上用场 + + + + + 使用从数据库,支持多个 + + 从数据库连接串 + + + + + 使用自定义数据库连接对象(放弃内置对象连接池技术) + + 数据库类型 + 数据库连接对象创建器 + 提供者的类型,一般不需要指定,如果一直提示“缺少 FreeSql 数据库实现包:FreeSql.Provider.MySql.dll,可前往 nuget 下载”的错误,说明反射获取不到类型,此时该参数可排上用场 + + + + + 【开发环境必备】自动同步实体结构到数据库,程序运行中检查实体表是否存在,然后创建或修改 + + true:运行时检查自动同步结构, false:不同步结构 + + + + + 将数据库的主键、自增、索引设置导入,适用 DbFirst 模式,无须在实体类型上设置 [Column(IsPrimary)] 或者 ConfigEntity。此功能目前可用于 mysql/sqlserver/postgresql/oracle。 + 本功能会影响 IFreeSql 首次访问的速度。 + 若使用 CodeFirst 创建索引后,又直接在数据库上建了索引,若无本功能下一次 CodeFirst 迁移时数据库上创建的索引将被删除 + + + + + + + 不使用命令参数化执行,针对 Insert/Update,也可临时使用 IInsert/IUpdate.NoneParameter() + + + + + + + 是否生成命令参数化执行,针对 lambda 表达式解析 + 注意:常量不会参数化,变量才会做参数化 + var id = 100; + fsql.Select<T>().Where(a => a.id == id) 会参数化 + fsql.Select<T>().Where(a => a.id == 100) 不会参数化 + + + + + + + 延时加载导航属性对象,导航属性需要声明 virtual + + + + + + + 监视数据库命令对象 + + 执行前 + 执行后,可监视执行性能 + + + + + 实体类名 -> 数据库表名,命名转换(类名、属性名都生效) + 优先级小于 [Table(Name = "xxx")]、[Column(Name = "xxx")] + + + + + + + 转小写同步结构 + + true:转小写, false:不转 + + + + + 转大写同步结构 + + true:转大写, false:不转 + + + + + 自动转换实体属性名称 Entity Property -> Db Filed + + *不会覆盖 [Column] 特性设置的Name + + + + + + + 指定事务对象 + + + + + + + 指定事务对象 + + + + + + + lambda表达式条件,仅支持实体基础成员(不包含导航对象) + 若想使用导航对象,请使用 ISelect.ToDelete() 方法 + + lambda表达式条件 + + + + + 原生sql语法条件,Where("id = ?id", new { id = 1 }) + + sql语法条件 + 参数 + + + + + 传入实体,将主键作为条件 + + 实体 + + + + + 传入实体集合,将主键作为条件 + + 实体集合 + + + + + 传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} + + 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 + 是否标识为NOT + + + + + 禁用全局过滤功能,不传参数时将禁用所有 + + 零个或多个过滤器名字 + + + + + 设置表名规则,可用于分库/分表,参数1:默认表名;返回值:新表名; + + + + + + + 动态Type,在使用 Delete<object> 后使用本方法,指定实体类型 + + + + + + + 返回即将执行的SQL语句 + + + + + + 执行SQL语句,返回影响的行数 + + + + + + 执行SQL语句,返回被删除的记录 + 注意:此方法只有 Postgresql/SqlServer 有效果 + + + + + + 指定事务对象 + + + + + + + 指定事务对象 + + + + + + + 追加准备插入的实体 + + 实体 + + + + + 追加准备插入的实体 + + 实体 + + + + + 追加准备插入的实体集合 + + 实体集合 + + + + + 只插入的列,InsertColumns(a => a.Name) | InsertColumns(a => new{a.Name,a.Time}) | InsertColumns(a => new[]{"name","time"}) + + lambda选择列 + + + + + 忽略的列,IgnoreColumns(a => a.Name) | IgnoreColumns(a => new{a.Name,a.Time}) | IgnoreColumns(a => new[]{"name","time"}) + + lambda选择列 + + + + + 指定可插入自增字段 + + + + + + 不使用参数化,可通过 IFreeSql.CodeFirst.IsNotCommandParameter 全局性设置 + + 是否不使用参数化 + + + + + 批量执行选项设置,一般不需要使用该方法 + 各数据库 values, parameters 限制不一样,默认设置: + MySql 5000 3000 + PostgreSQL 5000 3000 + SqlServer 1000 2100 + Oracle 500 999 + Sqlite 5000 999 + 若没有事务传入,内部(默认)会自动开启新事务,保证拆包执行的完整性。 + + 指定根据 values 数量拆分执行 + 指定根据 parameters 数量拆分执行 + 是否自动开启事务 + + + + + 设置表名规则,可用于分库/分表,参数1:默认表名;返回值:新表名; + + + + + + + 动态Type,在使用 Insert<object> 后使用本方法,指定实体类型 + + + + + + + 返回即将执行的SQL语句 + + + + + + 执行SQL语句,返回影响的行数 + + + + + + 执行SQL语句,返回自增值 + 注意:请检查实体类是否标记了 [Column(IsIdentity = true)] + + + + + + 执行SQL语句,返回插入后的记录 + 注意:此方法只有 Postgresql/SqlServer 有效果 + + + + + + 返回 DataTable 以便做 BulkCopy 数据做准备 + 此方法会处理: + 类型、表名、字段名映射 + IgnoreColumns、InsertColumns + + + + + + 自动产生 as1, as2, as3 .... 字段别名 + 这种方法可以最大程度防止多表,存在相同字段的问题 + + + + + 使用属性名作为字段别名 + + + + + 指定事务对象 + + + + + + + 指定连接对象 + + + + + + + 审核或跟踪 ToList 即将返回的数据 + + + + + + + 执行SQL查询,返回 DataTable + + + + + + 以字典的形式返回查询结果 + 注意:字典的特点会导致返回的数据无序 + + + + + + + + 执行SQL查询,返回 T1 实体所有字段的记录,记录不存在时返回 Count 为 0 的列表 + 注意: + 1、ToList(a => a) 可以返回 a 所有实体 + 2、ToList(a => new { a }) 这样也可以 + 3、ToList((a, b, c) => new { a, b, c }) 这样也可以 + 4、abc 怎么来的?请试试 fsql.Select<T1, T2, T3>() + + false: 返回 2级 LeftJoin/InnerJoin/RightJoin 对象;true: 返回所有 LeftJoin/InnerJoin/RightJoin 的导航数据 + + + + + 执行SQL查询,分块返回数据,可减少内存开销。比如读取10万条数据,每次返回100条处理。 + + 数据块的大小 + 处理数据块 + false: 返回 2级 LeftJoin/InnerJoin/RightJoin 对象;true: 返回所有 LeftJoin/InnerJoin/RightJoin 的导航数据 + + + + 执行SQL查询,返回 field 指定字段的记录,并以元组或基础类型(int,string,long)接收,记录不存在时返回 Count 为 0 的列表 + + + + + + + + 执行SQL查询,返回 T1 实体所有字段的第一条记录,记录不存在时返回 null + + + + + + 执行SQL查询,返回 T1 实体所有字段的第一条记录,记录不存在时返回 null + + + + + + 将查询转为删除对象,以便支持导航对象或其他查询功能删除数据,如下: + fsql.Select<T1>().Where(a => a.Options.xxx == 1).ToDelete().ExecuteAffrows() + 注意:此方法不是将数据查询到内存循环删除,上面的代码产生如下 SQL 执行: + DELETE FROM `T1` WHERE id in (select a.id from T1 a left join Options b on b.t1id = a.id where b.xxx = 1) + 复杂删除使用该方案的好处: + 1、删除前可预览测试数据,防止错误删除操作; + 2、支持更加复杂的删除操作(IDelete 默认只支持简单的操作); + + + + + + 将查询转为更新对象,以便支持导航对象或其他查询功能更新数据,如下: + fsql.Select<T1>().Where(a => a.Options.xxx == 1).ToUpdate().Set(a => a.Title, "111").ExecuteAffrows() + 注意:此方法不是将数据查询到内存循环更新,上面的代码产生如下 SQL 执行: + UPDATE `T1` SET Title = '111' WHERE id in (select a.id from T1 a left join Options b on b.t1id = a.id where b.xxx = 1) + 复杂更新使用该方案的好处: + 1、更新前可预览测试数据,防止错误更新操作; + 2、支持更加复杂的更新操作(IUpdate 默认只支持简单的操作); + + + + + + 设置表名规则,可用于分库/分表,参数1:实体类型;参数2:默认表名;返回值:新表名; + 设置多次,可查询分表后的多个子表记录,以 UNION ALL 形式执行。 + 如:select.AsTable((type, oldname) => "table_1").AsTable((type, oldname) => "table_2").AsTable((type, oldname) => "table_3").ToSql(a => a.Id); + select * from (SELECT a."Id" as1 FROM "table_1" a) ftb + UNION ALL select * from (SELECT a."Id" as1 FROM "table_2" a) ftb + UNION ALL select * from (SELECT a."Id" as1 FROM "table_3" a) ftb + 还可以这样:select.AsTable((a, b) => "(select * from tb_topic where clicks > 10)").Page(1, 10).ToList() + + + + + + + 设置别名规则,可用于拦截表别名,实现类似 sqlserver 的 with(nolock) 需求 + 如:select.AsAlias((_, old) => $"{old} with(lock)") + + + + + + + 动态Type,在使用 Select<object> 后使用本方法,指定实体类型 + + + + + + + 返回即将执行的SQL语句 + + 指定字段 + + + + + 执行SQL查询,是否有记录 + + + + + + 查询的记录数量 + + + + + + 查询的记录数量,以参数out形式返回 + + 返回的变量 + + + + + 指定从主库查询(默认查询从库) + + + + + + 左联查询,使用导航属性自动生成SQL + + 表达式 + + + + + 联接查询,使用导航属性自动生成SQL + + 表达式 + + + + + 右联查询,使用导航属性自动生成SQL + + 表达式 + + + + + 左联查询,指定关联的实体类型 + + 关联的实体类型 + 表达式 + + + + + 联接查询,指定关联的实体类型 + + 关联的实体类型 + 表达式 + + + + + 右联查询,指定关联的实体类型 + + 关联的实体类型 + 表达式 + + + + + 左联查询,使用原生sql语法,LeftJoin("type b on b.id = a.id and b.clicks > ?clicks", new { clicks = 1 }) + + sql语法条件 + 参数 + + + + + 联接查询,使用原生sql语法,InnerJoin("type b on b.id = a.id and b.clicks > ?clicks", new { clicks = 1 }) + + sql语法条件 + 参数 + + + + + 右联查询,使用原生sql语法,RightJoin("type b on b.id = a.id and b.clicks > ?clicks", new { clicks = 1 }) + + sql语法条件 + 参数 + + + + + 在 JOIN 位置插入 SQL 内容 + 如:.RawJoin("OUTER APPLY ( select id from t2 ) b") + + + + + + + 原生sql语法条件,Where("id = ?id", new { id = 1 }) + + sql语法条件 + 参数 + + + + + 原生sql语法条件,WhereIf(true, "id = ?id", new { id = 1 }) + + true 时生效 + sql语法条件 + 参数 + + + + + 禁用全局过滤功能,不传参数时将禁用所有 + + 零个或多个过滤器名字 + + + + + 排他更新锁 + 注意:务必在开启事务后使用该功能 + MySql: for update + SqlServer: With(UpdLock, RowLock, NoWait) + PostgreSQL: for update nowait + Oracle: for update nowait + Sqlite: 无效果 + 达梦: for update nowait + + noawait + + + + + 按原生sql语法分组,GroupBy("concat(name, ?cc)", new { cc = 1 }) + + sql语法 + 参数 + + + + + 按原生sql语法聚合条件过滤,Having("count(name) = ?cc", new { cc = 1 }) + + sql语法条件 + 参数 + + + + + 按原生sql语法排序,OrderBy("count(name) + ?cc desc", new { cc = 1 }) + + sql语法 + 参数 + + + + + 按原生sql语法排序,OrderBy(true, "count(name) + ?cc desc", new { cc = 1 }) + + true 时生效 + sql语法 + 参数 + + + + + 查询向后偏移行数 + + + + + + + 查询向后偏移行数 + + 行数 + + + + + 查询多少条数据 + + + + + + + 查询多少条数据 + + + + + + + 分页 + + 第几页 + 每页多少 + + + + + 查询数据前,去重 + + .Distinct().ToList(x => x.GroupName) 对指定字段去重 + + + .Distinct().ToList() 对整个查询去重 + + + + + + + 执行SQL查询,是否有记录 + + lambda表达式 + + + + + 执行SQL查询,返回 DataTable + + + + + + 执行SQL查询,返回指定字段的记录,记录不存在时返回 Count 为 0 的列表 + + 返回类型 + 选择列 + + + + + 执行SQL查询,返回 TDto 映射的字段,记录不存在时返回 Count 为 0 的列表 + + + + + + + 执行SQL查询,返回指定字段的记录的第一条记录,记录不存在时返回 TReturn 默认值 + + 返回类型 + 选择列 + + + + + 执行SQL查询,返回 TDto 映射的字段,记录不存在时返回 Dto 默认值 + + + + + + + 执行SQL查询,返回指定字段的记录的第一条记录,记录不存在时返回 TReturn 默认值 + + 返回类型 + 选择列 + + + + + 执行SQL查询,返回 TDto 映射的字段,记录不存在时返回 Dto 默认值 + + + + + + + 返回即将执行的SQL语句 + + 返回类型 + 选择列 + 字段别名 + + + + + 执行SQL查询,返回指定字段的聚合结果 + + + + + + + + 求和 + + 返回类型 + 列 + + + + + 最小值 + + 返回类型 + 列 + + + + + 最大值 + + 返回类型 + 列 + + + + + 平均值 + + 返回类型 + 列 + + + + + 指定别名 + + 别名 + + + + + 多表查询 + + + + + + + + 多表查询 + + + + + + + + + 多表查询 + + + + + + + + + + 多表查询 + + + + + + + + + + + 多表查询 + + + + + + + + + + + + 多表查询 + + + + + + + + + + + + + 多表查询 + + + + + + + + + + + + + + 多表查询 + + + + + + + + + + + + + + + 多表查询 + + + + + + + + + + + + + + + + 查询条件,Where(a => a.Id > 10),支持导航对象查询,Where(a => a.Author.Email == "2881099@qq.com") + + lambda表达式 + + + + + 查询条件,Where(true, a => a.Id > 10),支导航对象查询,Where(true, a => a.Author.Email == "2881099@qq.com") + + true 时生效 + lambda表达式 + + + + + 多表条件查询 + + + lambda表达式 + + + + + 多表条件查询 + + + lambda表达式 + + + + + 多表条件查询 + + + + lambda表达式 + + + + + 多表条件查询 + + + + + lambda表达式 + + + + + 多表条件查询 + + + + + lambda表达式 + + + + + 传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} + + 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 + 是否标识为NOT + + + + + 多表查询时,该方法标记后,表达式条件将对所有表进行附加 + + 例如:软删除、租户,每个表都给条件,挺麻烦的 + + fsql.Select<T1>().LeftJoin<T2>(...).Where<T2>((t1, t2 => t1.IsDeleted == false && t2.IsDeleted == false) + + 修改:fsql.Select<T1>().LeftJoin<T2>(...).WhereCascade(t1 => t1.IsDeleted == false) + + 当其中的实体可附加表达式才会进行,表越多时收益越大 + + + + + + + 按选择的列分组,GroupBy(a => a.Name) | GroupBy(a => new{a.Name,a.Time}) + + + + + + + 按列排序,OrderBy(a => a.Time) + + + + + + + + 按列排序,OrderBy(true, a => a.Time) + + + true 时生效 + + + + + + 按列倒向排序,OrderByDescending(a => a.Time) + + 列 + + + + + 按列倒向排序,OrderByDescending(true, a => a.Time) + + true 时生效 + 列 + + + + + 贪婪加载导航属性,如果查询中已经使用了 a.Parent.Parent 类似表达式,则可以无需此操作 + + + 选择一个导航属性 + + + + + 贪婪加载集合的导航属性,其实是分两次查询,ToList 后进行了数据重装 + 文档:https://github.com/2881099/FreeSql/wiki/%e8%b4%aa%e5%a9%aa%e5%8a%a0%e8%bd%bd#%E5%AF%BC%E8%88%AA%E5%B1%9E%E6%80%A7-onetomanymanytomany + + + 选择一个集合的导航属性,如: .IncludeMany(a => a.Tags) + 可以 .Where 设置临时的关系映射,如: .IncludeMany(a => a.Tags.Where(tag => tag.TypeId == a.Id)) + 可以 .Take(5) 每个子集合只取5条,如: .IncludeMany(a => a.Tags.Take(5)) + 可以 .Select 设置只查询部分字段,如: (a => new TNavigate { Title = a.Title }) + + 即能 ThenInclude,还可以二次过滤(这个 EFCore 做不到?) + + + + + 实现 select .. from ( select ... from t ) a 这样的功能 + 使用 AsTable 方法也可以达到效果 + + SQL语句 + + + + + 查询条件,Where(a => a.Id > 10),支持导航对象查询,Where(a => a.Author.Email == "2881099@qq.com") + + lambda表达式 + + + + + 查询条件,Where(true, a => a.Id > 10),支导航对象查询,Where(true, a => a.Author.Email == "2881099@qq.com") + + true 时生效 + lambda表达式 + + + + + 按列排序,OrderBy(a => a.Time) + + + + + + + + 按列倒向排序,OrderByDescending(a => a.Time) + + 列 + + + + + 按聚合条件过滤,Where(a => a.Count() > 10) + + lambda表达式 + + + + + 按列排序,OrderBy(a => a.Time) + + + + + + + + 按列倒向排序,OrderByDescending(a => a.Time) + + 列 + + + + + 执行SQL查询,返回指定字段的记录,记录不存在时返回 Count 为 0 的列表 + + 返回类型 + 选择列 + + + + + 【linq to sql】专用方法,不建议直接使用 + + + + + 返回即将执行的SQL语句 + + 返回类型 + 选择列 + + + + + 返回即将执行的SQL语句 + + 指定字段 + + + + + 查询向后偏移行数 + + + + + + + 查询向后偏移行数 + + 行数 + + + + + 查询多少条数据 + + + + + + + 查询多少条数据 + + + + + + + 分页 + + 第几页 + 每页多少 + + + + + 查询的记录数量 + + + + + + 查询的记录数量,以参数out形式返回 + + 返回的变量 + + + + + 分组的数据 + + + + + 记录总数 + + + + + + 求和 + + + + + + + + 平均值 + + + + + + + + 最大值 + + + + + + + + 最小值 + + + + + + + 所有元素 + + + + + 指定事务对象 + + + + + + + 指定事务对象 + + + + + + + 不使用参数化,可通过 IFreeSql.CodeFirst.IsNotCommandParameter 全局性设置 + + 是否不使用参数化 + + + + + 批量执行选项设置,一般不需要使用该方法 + 各数据库 rows, parameters 限制不一样,默认设置: + MySql 500 3000 + PostgreSQL 500 3000 + SqlServer 500 2100 + Oracle 200 999 + Sqlite 200 999 + 若没有事务传入,内部(默认)会自动开启新事务,保证拆包执行的完整性。 + + 指定根据 rows 数量拆分执行 + 指定根据 parameters 数量拆分执行 + 是否自动开启事务 + + + + + 更新数据,设置更新的实体 + + 实体 + + + + + 更新数据,设置更新的实体集合 + + 实体集合 + + + + + 忽略的列,IgnoreColumns(a => a.Name) | IgnoreColumns(a => new{a.Name,a.Time}) | IgnoreColumns(a => new[]{"name","time"}) + + lambda选择列 + + + + + 忽略的列 + + 属性名,或者字段名 + + + + + 指定的列,UpdateColumns(a => a.Name) | UpdateColumns(a => new{a.Name,a.Time}) | UpdateColumns(a => new[]{"name","time"}) + + lambda选择列 + + + + + 指定的列 + + 属性名,或者字段名 + + + + + 设置列的新值,Set(a => a.Name, "newvalue") + + + lambda选择列 + 新值 + + + + + 设置列的的新值为基础上增加,格式:Set(a => a.Clicks + 1) 相当于 clicks=clicks+1 + + 指定更新,格式:Set(a => new T { Clicks = a.Clicks + 1, Time = DateTime.Now }) 相当于 set clicks=clicks+1,time='2019-06-19....' + + + + + + + + 设置值,自定义SQL语法,SetRaw("title = ?title", new { title = "newtitle" }) + + sql语法 + 参数 + + + + + 设置更新的列 + + SetDto(new { title = "xxx", clicks = 2 }) + + SetDto(new Dictionary<string, object> { ["title"] = "xxx", ["clicks"] = 2 }) + + dto 或 Dictionary<string, object> + + + + + lambda表达式条件,仅支持实体基础成员(不包含导航对象) + 若想使用导航对象,请使用 ISelect.ToUpdate() 方法 + + lambda表达式条件 + + + + + 原生sql语法条件,Where("id = ?id", new { id = 1 }) + + sql语法条件 + 参数 + + + + + 传入实体,将主键作为条件 + + 实体 + + + + + 传入实体集合,将主键作为条件 + + 实体集合 + + + + + 传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} + + 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 + 是否标识为NOT + + + + + 禁用全局过滤功能,不传参数时将禁用所有 + + 零个或多个过滤器名字 + + + + + 设置表名规则,可用于分库/分表,参数1:默认表名;返回值:新表名; + + + + + + + 动态Type,在使用 Update<object> 后使用本方法,指定实体类型 + + + + + + + 返回即将执行的SQL语句 + + + + + + 执行SQL语句,返回影响的行数 + + + + + + 执行SQL语句,返回更新后的记录 + 注意:此方法只有 Postgresql/SqlServer 有效果 + + + + + + 主库连接池 + + + + + 从库连接池 + + + + + 数据库类型 + + + + + UseConnectionString 时候的值 + + + + + UseSalve 时候的值 + + + + + 唯一标识 + + + + + 开启事务(不支持异步),60秒未执行完成(可能)被其他线程事务自动提交 + + 事务体 () => {} + + + + 开启事务(不支持异步) + + 超时,未执行完成(可能)被其他线程事务自动提交 + 事务体 () => {} + + + + 开启事务(不支持异步) + + + 事务体 () => {} + 超时,未执行完成(可能)被其他线程事务自动提交 + + + + 当前线程的事务 + + + + + 查询,若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】 + + + + + + + + + 查询,ExecuteReader(dr => {}, "select * from user where age > ?age", new { age = 25 }) + + + + + + + 查询 + + + + + + + 查询,ExecuteArray("select * from user where age > ?age", new { age = 25 }) + + + + + + + + 查询 + + + + + + + 查询,ExecuteDataSet("select * from user where age > ?age; select 2", new { age = 25 }) + + + + + + + + 查询 + + + + + + + 查询,ExecuteDataTable("select * from user where age > ?age", new { age = 25 }) + + + + + + + + 在【主库】执行 + + + + + + + + 在【主库】执行,ExecuteNonQuery("delete from user where age > ?age", new { age = 25 }) + + + + + + + + 在【主库】执行 + + + + + + + + 在【主库】执行,ExecuteScalar("select 1 from user where age > ?age", new { age = 25 }) + + + + + + + + 执行SQL返回对象集合,Query<User>("select * from user where age > ?age", new SqlParameter { ParameterName = "age", Value = 25 }) + + + + + + + + + + 执行SQL返回对象集合,Query<User>("select * from user where age > ?age", new { age = 25 }) + + + + + + + + + 执行SQL返回对象集合,Query<User>("select * from user where age > ?age; select * from address", new SqlParameter { ParameterName = "age", Value = 25 }) + + + + + + + + + + 执行SQL返回对象集合,Query<User>("select * from user where age > ?age; select * from address", new { age = 25 }) + + + + + + + + + 可自定义解析表达式 + + + + + 自定义实体的配置,方便和多个 ORM 共同使用 + + + + + 自定义实体的属性配置,方便和多个 ORM 共同使用 + + + + + 增删查改,执行命令之前触发 + + + + + 增删查改,执行命令完成后触发 + + + + + CodeFirst迁移,执行之前触发 + + + + + CodeFirst迁移,执行完成触发 + + + + + Insert/Update自动值处理 + + + + + 监视数据库命令对象(执行前,调试) + + + + + 监视数据库命令对象(执行后,用于监视执行性能) + + + + + 跟踪开始 + + + + + 跟踪结束 + + + + + 内置解析功能,可辅助您进行解析 + + + + + 需要您解析的表达式 + + + + + 解析后的内容 + + + + + 实体类型 + + + + + 实体配置 + + + + + 索引配置 + + + + + 实体类型 + + + + + 实体的属性 + + + + + 实体的属性配置 + + + + + 标识符,可将 CurdBefore 与 CurdAfter 进行匹配 + + + + + 操作类型 + + + + + 实体类型 + + + + + 实体类型的元数据 + + + + + 执行的 SQL + + + + + 参数化命令 + + + + + 发生的错误 + + + + + 执行SQL命令,返回的结果 + + + + + 耗时(单位:Ticks) + + + + + 耗时(单位:毫秒) + + + + + 标识符,可将 SyncStructureBeforeEventArgs 与 SyncStructureAfterEventArgs 进行匹配 + + + + + 实体类型 + + + + + 执行的 SQL + + + + + 发生的错误 + + + + + 耗时(单位:Ticks) + + + + + 耗时(单位:毫秒) + + + + + 类型 + + + + + 属性列的元数据 + + + + + 反射的属性信息 + + + + + 获取实体的属性值,也可以设置实体的属性新值 + + + + + 标识符,可将 CommandBefore 与 CommandAfter 进行匹配 + + + + + 发生的错误 + + + + + 执行SQL命令,返回的结果 + + + + + 耗时(单位:Ticks) + + + + + 耗时(单位:毫秒) + + + + + 标识符,可将 TraceBeforeEventArgs 与 TraceAfterEventArgs 进行匹配 + + + + + 备注 + + + + + 发生的错误 + + + + + 耗时(单位:Ticks) + + + + + 耗时(单位:毫秒) + + + + + 【开发环境必备】自动同步实体结构到数据库,程序运行中检查实体表是否存在,然后创建或修改 + + + + + 转小写同步结构,适用 PostgreSQL + + + + + 转大写同步结构,适用 Oracle/达梦 + + + + + 将数据库的主键、自增、索引设置导入,适用 DbFirst 模式,无须在实体类型上设置 [Column(IsPrimary)] 或者 ConfigEntity。此功能目前可用于 mysql/sqlserver/postgresql/oracle。 + 本功能会影响 IFreeSql 首次访问的速度。 + 若使用 CodeFirst 创建索引后,又直接在数据库上建了索引,若无本功能下一次 CodeFirst 迁移时数据库上创建的索引将被删除 + + + + + 不使用命令参数化执行,针对 Insert/Update + + + + + 是否生成命令参数化执行,针对 lambda 表达式解析 + 注意:常量不会参数化,变量才会做参数化 + var id = 100; + fsql.Select<T>().Where(a => a.id == id) 会参数化 + fsql.Select<T>().Where(a => a.id == 100) 不会参数化 + + + + + 延时加载导航属性对象,导航属性需要声明 virtual + + + + + 将实体类型与数据库对比,返回DDL语句 + + + + + + + 将实体类型集合与数据库对比,返回DDL语句 + + 实体类型 + + + + + 将实体类型与数据库对比,返回DDL语句(指定表名) + + 实体类型 + 指定表名对比 + + + + + 同步实体类型到数据库 + + + + + + 同步实体类型集合到数据库 + + + + + + 同步实体类型到数据库(指定表名) + + 实体类型 + 指定表名对比 + + + + 根据 System.Type 获取数据库信息 + + + + + + + 在外部配置实体的特性 + + + + + + + + 在外部配置实体的特性 + + + + + + + + 获取在外部配置实体的特性 + + + 未使用ConfigEntity配置时,返回null + + + + 获取实体类核心配置 + + + + + + + 获取所有数据库 + + + + + + 获取指定数据库的表信息,包括表、列详情、主键、唯一键、索引、外键、备注 + + + + + + + 获取数据库枚举类型int值 + + + + + + + 获取c#转换,(int)、(long) + + + + + + + 获取c#值 + + + + + + + 获取c#类型,int、long + + + + + + + 获取c#类型对象 + + + + + + + 获取ado.net读取方法, GetBoolean、GetInt64 + + + + + + + 序列化 + + + + + + + 反序列化 + + + + + + + 获取数据库枚举类型,适用 PostgreSQL + + + + + + + AsType, Ctor, ClearData 三处地方需要重新加载 + + + + + AsType, Ctor, ClearData 三处地方需要重新加载 + + + + + 通过属性的注释文本,通过 xml 读取 + + + Dict:key=属性名,value=注释 + + + + 创建一个过滤器 + + + 名字 + 表达式 + + + + + 中间表,多对多 + + + + + 是否可用 + + + + + 不可用错误 + + + + + 不可用时间 + + + + + 将对象池设置为不可用,后续 Get/GetAsync 均会报错,同时启动后台定时检查服务恢复可用 + + + 由【可用】变成【不可用】时返回true,否则返回false + + + + 统计对象池中的对象 + + + + + 统计对象池中的对象(完整) + + + + + 获取资源 + + 超时 + + + + + 使用完毕后,归还资源 + + 对象 + 是否重新创建 + + + + 名称 + + + + + 池容量 + + + + + 默认获取超时设置 + + + + + 空闲时间,获取时若超出,则重新创建 + + + + + 异步获取排队队列大小,小于等于0不生效 + + + + + 获取超时后,是否抛出异常 + + + + + 监听 AppDomain.CurrentDomain.ProcessExit/Console.CancelKeyPress 事件自动释放 + + + + + 后台定时检查可用性间隔秒数 + + + + + 对象池的对象被创建时 + + 返回被创建的对象 + + + + 销毁对象 + + 资源对象 + + + + 从对象池获取对象超时的时候触发,通过该方法统计 + + + + + 从对象池获取对象成功的时候触发,通过该方法统计或初始化对象 + + 资源对象 + + + + 归还对象给对象池的时候触发 + + 资源对象 + + + + 检查可用性 + + 资源对象 + + + + + 事件:可用时触发 + + + + + 事件:不可用时触发 + + + + + 所属对象池 + + + + + 在对象池中的唯一标识 + + + + + 资源对象 + + + + + 被获取的总次数 + + + + 最后获取时的时间 + + + + 最后归还时的时间 + + + + + 创建时间 + + + + + 最后获取时的线程id + + + + + 最后归还时的线程id + + + + + 重置 Value 值 + + + + + 对象池管理类 + + 对象类型 + + + + 后台定时检查可用性 + + + + + + 创建对象池 + + 池大小 + 池内对象的创建委托 + 获取池内对象成功后,进行使用前操作 + + + + 创建对象池 + + 策略 + + + + 获取可用资源,或创建资源 + + + + + + 不进行任何处理 + + + + + 将帕斯卡命名字符串转换为下划线分隔字符串 + + BigApple -> Big_Apple + + + + + 将帕斯卡命名字符串转换为下划线分隔字符串,且转换为全大写 + + BigApple -> BIG_APPLE + + + + + 将帕斯卡命名字符串转换为下划线分隔字符串,且转换为全小写 + + BigApple -> big_apple + + + + + 将字符串转换为大写 + + BigApple -> BIGAPPLE + + + + + 将字符串转换为小写 + + BigApple -> bigapple + + + + + 不进行任何处理 + + + + + 将帕斯卡命名字符串转换为下划线分隔字符串 + + BigApple -> Big_Apple + + + + + 将帕斯卡命名字符串转换为下划线分隔字符串,且转换为全大写 + + BigApple -> BIG_APPLE + + + + + 将帕斯卡命名字符串转换为下划线分隔字符串,且转换为全小写 + + BigApple -> big_apple + + + + + 将字符串转换为大写 + + BigApple -> BIGAPPLE + + + + + 将字符串转换为小写 + + BigApple -> bigapple + + + + + C#: that >= between && that <= and + SQL: that BETWEEN between AND and + + + + + + + + + 注意:这个方法和 Between 有细微区别 + C#: that >= start && that < end + SQL: that >= start and that < end + + + + + + + + + 获取 Type 的原始 c# 文本表示 + + + + + + + 测量两个经纬度的距离,返回单位:米 + + 经纬坐标1 + 经纬坐标2 + 返回距离(单位:米) + + + + 将 IEnumable<T> 转成 ISelect<T>,以便使用 FreeSql 的查询功能。此方法用于 Lambad 表达式中,快速进行集合导航的查询。 + + + + + + + + 多表查询 + + + + + + 多表查询 + + + + + + 多表查询 + + + + + + 多表查询 + + + + + + 多表查询 + + + + + + 多表查询 + + + + + + 多表查询 + + + + + + 多表查询 + + + + + + 多表查询 + + + + + + 本方法实现从已知的内存 List 数据,进行和 ISelect.IncludeMany 相同功能的贪婪加载 + 示例:new List<Song>(new[] { song1, song2, song3 }).IncludeMany(g.sqlite, a => a.Tags); + 文档:https://github.com/2881099/FreeSql/wiki/%e8%b4%aa%e5%a9%aa%e5%8a%a0%e8%bd%bd#%E5%AF%BC%E8%88%AA%E5%B1%9E%E6%80%A7-onetomanymanytomany + + + 选择一个集合的导航属性,如: .IncludeMany(a => a.Tags) + 可以 .Where 设置临时的关系映射,如: .IncludeMany(a => a.Tags.Where(tag => tag.TypeId == a.Id)) + 可以 .Take(5) 每个子集合只取5条,如: .IncludeMany(a => a.Tags.Take(5)) + 可以 .Select 设置只查询部分字段,如: (a => new TNavigate { Title = a.Title }) + + 即能 ThenInclude,还可以二次过滤(这个 EFCore 做不到?) + + + + + 查询数据,加工为树型 List 返回 + 注意:实体需要配置父子导航属性 + + + + + + + + 使用 and 拼接两个 lambda 表达式 + + + + + + 使用 and 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 将 lambda 表达式取反 + + + true 时生效 + + + + + 使用 and 拼接两个 lambda 表达式 + + + + + + 使用 and 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 将 lambda 表达式取反 + + + true 时生效 + + + + + 使用 and 拼接两个 lambda 表达式 + + + + + + 使用 and 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 将 lambda 表达式取反 + + + true 时生效 + + + + + 使用 and 拼接两个 lambda 表达式 + + + + + + 使用 and 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 将 lambda 表达式取反 + + + true 时生效 + + + + + 使用 and 拼接两个 lambda 表达式 + + + + + + 使用 and 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 将 lambda 表达式取反 + + + true 时生效 + + + + + 生成类似Mongodb的ObjectId有序、不重复Guid + + + + + + 插入数据 + + + + + + + 插入数据,传入实体 + + + + + + + + 插入数据,传入实体数组 + + + + + + + + 插入数据,传入实体集合 + + + + + + + + 插入数据,传入实体集合 + + + + + + + + 修改数据 + + + + + + + 修改数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} + + + 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 + + + + + 查询数据 + + + + + + + 查询数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} + + + 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 + + + + + 删除数据 + + + + + + + 删除数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} + + + 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 + + + + + 开启事务(不支持异步),60秒未执行完成(可能)被其他线程事务自动提交 + + 事务体 () => {} + + + + 开启事务(不支持异步) + + 超时,未执行完成(可能)被其他线程事务自动提交 + 事务体 () => {} + + + + 开启事务(不支持异步) + + + 事务体 () => {} + 超时,未执行完成(可能)被其他线程事务自动提交 + + + + 数据库访问对象 + + + + + 所有拦截方法都在这里 + + + + + CodeFirst 模式开发相关方法 + + + + + DbFirst 模式开发相关方法 + + + + + 全局过滤设置,可默认附加为 Select/Update/Delete 条件 + + + + + + + + + 使用 or 拼接两个 lambda 表达式 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 将 lambda 表达式取反 + + + true 时生效 + + + + + 生成类似Mongodb的ObjectId有序、不重复Guid + + + + + + 插入数据 + + + + + + + 插入数据,传入实体 + + + + + + + + 插入数据,传入实体数组 + + + + + + + + 插入数据,传入实体集合 + + + + + + + + 插入数据,传入实体集合 + + + + + + + + 修改数据 + + + + + + + 修改数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} + + + 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 + + + + + 查询数据 + + + + + + + 查询数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} + + + 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 + + + + + 删除数据 + + + + + + + 删除数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1} + + + 主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合 + + + + + 开启事务(不支持异步),60秒未执行完成(可能)被其他线程事务自动提交 + + 事务体 () => {} + + + + 开启事务(不支持异步) + + 超时,未执行完成(可能)被其他线程事务自动提交 + 事务体 () => {} + + + + 开启事务(不支持异步) + + + 事务体 () => {} + 超时,未执行完成(可能)被其他线程事务自动提交 + + + + 数据库访问对象 + + + + + 所有拦截方法都在这里 + + + + + CodeFirst 模式开发相关方法 + + + + + DbFirst 模式开发相关方法 + + + + + 全局过滤设置,可默认附加为 Select/Update/Delete 条件 + + + + diff --git a/FreeSql/Internal/CommonProvider/InsertProvider.cs b/FreeSql/Internal/CommonProvider/InsertProvider.cs index 313434de..ca5f7574 100644 --- a/FreeSql/Internal/CommonProvider/InsertProvider.cs +++ b/FreeSql/Internal/CommonProvider/InsertProvider.cs @@ -134,7 +134,7 @@ namespace FreeSql.Internal.CommonProvider public static void AuditDataValue(object sender, T1 data, IFreeSql orm, TableInfo table, Dictionary changedDict) { if (data == null) return; - if (typeof(T1) == typeof(object) && data.GetType() != table.Type) + if (typeof(T1) == typeof(object) && new[] { table.Type, table.TypeLazy }.Contains(data.GetType()) == false) throw new Exception($"操作的数据类型({data.GetType().DisplayCsharp()}) 与 AsType({table.Type.DisplayCsharp()}) 不一致,请检查。"); foreach (var col in table.Columns.Values) { diff --git a/FreeSql/Internal/CommonProvider/UpdateProvider.cs b/FreeSql/Internal/CommonProvider/UpdateProvider.cs index f5ad6a9c..d4100b04 100644 --- a/FreeSql/Internal/CommonProvider/UpdateProvider.cs +++ b/FreeSql/Internal/CommonProvider/UpdateProvider.cs @@ -351,7 +351,7 @@ namespace FreeSql.Internal.CommonProvider { if (orm.Aop.AuditValueHandler == null) return; if (data == null) return; - if (typeof(T1) == typeof(object) && data.GetType() != table.Type) + if (typeof(T1) == typeof(object) && new[] { table.Type, table.TypeLazy }.Contains(data.GetType()) == false) throw new Exception($"操作的数据类型({data.GetType().DisplayCsharp()}) 与 AsType({table.Type.DisplayCsharp()}) 不一致,请检查。"); foreach (var col in table.Columns.Values) {