diff --git a/Examples/efcore_to_freesql/Startup.cs b/Examples/efcore_to_freesql/Startup.cs index 0fabf866..6d98c5e5 100644 --- a/Examples/efcore_to_freesql/Startup.cs +++ b/Examples/efcore_to_freesql/Startup.cs @@ -27,6 +27,8 @@ namespace efcore_to_freesql .UseAutoSyncStructure(true) .Build(); + FreeSql.Extensions.EfCoreFluentApi.ICodeFirstExtensions.Test(Fsql); + DBContexts.BaseDBContext.Fsql = Fsql; var sql11 = Fsql.Select().ToSql(); @@ -64,13 +66,20 @@ namespace efcore_to_freesql public void ConfigureServices(IServiceCollection services) { + services.AddControllersWithViews(); services.AddSingleton(Fsql); services.AddMvc(); } public void Configure(IApplicationBuilder app) { - app.UseDeveloperExceptionPage(); + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + Console.OutputEncoding = Encoding.GetEncoding("GB2312"); + Console.InputEncoding = Encoding.GetEncoding("GB2312"); + + app.UseHttpMethodOverride(new HttpMethodOverrideOptions { FormFieldName = "X-Http-Method-Override" }); + app.UseDeveloperExceptionPage(); + app.UseRouting(); app.UseEndpoints(a => a.MapControllers()); } } diff --git a/Examples/efcore_to_freesql/efcore_to_freesql.csproj b/Examples/efcore_to_freesql/efcore_to_freesql.csproj index 3769825e..3624b40c 100644 --- a/Examples/efcore_to_freesql/efcore_to_freesql.csproj +++ b/Examples/efcore_to_freesql/efcore_to_freesql.csproj @@ -10,7 +10,9 @@ + + diff --git a/Extensions/FreeSql.Extensions.EfCoreFluentApi/EfCoreTableFluent.cs b/Extensions/FreeSql.Extensions.EfCoreFluentApi/EfCoreTableFluent.cs index b9ab2cb2..db7dd65f 100644 --- a/Extensions/FreeSql.Extensions.EfCoreFluentApi/EfCoreTableFluent.cs +++ b/Extensions/FreeSql.Extensions.EfCoreFluentApi/EfCoreTableFluent.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Linq.Expressions; using FreeSql.DataAnnotations; @@ -7,9 +8,11 @@ namespace FreeSql.Extensions.EfCoreFluentApi { public class EfCoreTableFluent { + IFreeSql _fsql; TableFluent _tf; - internal EfCoreTableFluent(TableFluent tf) + internal EfCoreTableFluent(IFreeSql fsql, TableFluent tf) { + _fsql = fsql; _tf = tf; } @@ -33,8 +36,10 @@ namespace FreeSql.Extensions.EfCoreFluentApi #region HasKey public EfCoreTableFluent HasKey(Expression> key) { - if (key?.Body == null) return this; - var exp = key.Body; + var exp = key?.Body; + if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; + if (exp == null) throw new ArgumentException("参数错误 key 不能为 null"); + switch (exp.NodeType) { case ExpressionType.MemberAccess: @@ -52,8 +57,9 @@ namespace FreeSql.Extensions.EfCoreFluentApi #region HasIndex public HasIndexFluent HasIndex(Expression> index) { - if (index?.Body == null) throw new ArgumentException("参数错误 index 不能为 null"); - var exp = index.Body; + var exp = index?.Body; + if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; + if (exp == null) throw new ArgumentException("参数错误 index 不能为 null"); var indexName = $"idx_{Guid.NewGuid().ToString("N").Substring(0, 8)}"; var columns = new List(); @@ -102,8 +108,9 @@ namespace FreeSql.Extensions.EfCoreFluentApi #region HasOne public HasOneFluent HasOne(Expression> one) { - if (one?.Body == null) throw new ArgumentException("参数错误 one 不能为 null"); - var exp = one.Body; + var exp = one?.Body; + if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; + if (exp == null) throw new ArgumentException("参数错误 one 不能为 null"); var oneProperty = ""; switch (exp.NodeType) @@ -113,10 +120,11 @@ namespace FreeSql.Extensions.EfCoreFluentApi break; } if (string.IsNullOrEmpty(oneProperty)) throw new ArgumentException("参数错误 one"); - return new HasOneFluent(_tf, oneProperty); + return new HasOneFluent(_fsql, _tf, oneProperty); } public class HasOneFluent { + IFreeSql _fsql; TableFluent _tf; string _selfProperty; string _selfBind; @@ -124,15 +132,17 @@ namespace FreeSql.Extensions.EfCoreFluentApi string _withOneProperty; string _withOneBind; - internal HasOneFluent(TableFluent modelBuilder, string oneProperty) + internal HasOneFluent(IFreeSql fsql, TableFluent modelBuilder, string oneProperty) { + _fsql = fsql; _tf = modelBuilder; _selfProperty = oneProperty; } public HasOneFluent WithMany(Expression> many) { - if (many?.Body == null) throw new ArgumentException("参数错误 many 不能为 null"); - var exp = many.Body; + var exp = many?.Body; + if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; + if (exp == null) throw new ArgumentException("参数错误 many 不能为 null"); switch (exp.NodeType) { @@ -142,13 +152,14 @@ namespace FreeSql.Extensions.EfCoreFluentApi } if (string.IsNullOrEmpty(_withManyProperty)) throw new ArgumentException("参数错误 many"); if (string.IsNullOrEmpty(_selfBind) == false) - _tf.ConfigEntity(eb2 => eb2.Navigate(_withManyProperty, _selfBind)); + _fsql.CodeFirst.ConfigEntity(eb2 => eb2.Navigate(_withManyProperty, _selfBind)); return this; } public HasOneFluent WithOne(Expression> one, Expression> foreignKey) { - if (one?.Body == null) throw new ArgumentException("参数错误 one 不能为 null"); - var exp = one.Body; + var exp = one?.Body; + if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; + if (exp == null) throw new ArgumentException("参数错误 one 不能为 null"); switch (exp.NodeType) { @@ -158,8 +169,9 @@ namespace FreeSql.Extensions.EfCoreFluentApi } if (string.IsNullOrEmpty(_withOneProperty)) throw new ArgumentException("参数错误 one"); - if (foreignKey?.Body == null) throw new ArgumentException("参数错误 foreignKey 不能为 null"); - exp = foreignKey.Body; + exp = foreignKey?.Body; + if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; + if (exp == null) throw new ArgumentException("参数错误 foreignKey 不能为 null"); switch (exp.NodeType) { @@ -176,13 +188,14 @@ namespace FreeSql.Extensions.EfCoreFluentApi } if (string.IsNullOrEmpty(_withOneBind)) throw new ArgumentException("参数错误 foreignKey"); if (string.IsNullOrEmpty(_selfBind) == false) - _tf.ConfigEntity(eb2 => eb2.Navigate(_withOneProperty, _withOneBind)); + _fsql.CodeFirst.ConfigEntity(eb2 => eb2.Navigate(_withOneProperty, _withOneBind)); return this; } public HasOneFluent HasForeignKey(Expression> foreignKey) { - if (foreignKey?.Body == null) throw new ArgumentException("参数错误 foreignKey 不能为 null"); - var exp = foreignKey.Body; + var exp = foreignKey?.Body; + if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; + if (exp == null) throw new ArgumentException("参数错误 foreignKey 不能为 null"); switch (exp.NodeType) { @@ -200,9 +213,9 @@ namespace FreeSql.Extensions.EfCoreFluentApi if (string.IsNullOrEmpty(_selfBind)) throw new ArgumentException("参数错误 foreignKey"); _tf.Navigate(_selfProperty, _selfBind); if (string.IsNullOrEmpty(_withManyProperty) == false) - _tf.ConfigEntity(eb2 => eb2.Navigate(_withManyProperty, _selfBind)); + _fsql.CodeFirst.ConfigEntity(eb2 => eb2.Navigate(_withManyProperty, _selfBind)); if (string.IsNullOrEmpty(_withOneProperty) == false && string.IsNullOrEmpty(_withOneBind) == false) - _tf.ConfigEntity(eb2 => eb2.Navigate(_withOneProperty, _withOneBind)); + _fsql.CodeFirst.ConfigEntity(eb2 => eb2.Navigate(_withOneProperty, _withOneBind)); return this; } } @@ -211,8 +224,9 @@ namespace FreeSql.Extensions.EfCoreFluentApi #region HasMany public HasManyFluent HasMany(Expression>> many) { - if (many?.Body == null) throw new ArgumentException("参数错误 many 不能为 null"); - var exp = many.Body; + var exp = many?.Body; + if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; + if (exp == null) throw new ArgumentException("参数错误 many 不能为 null"); var manyProperty = ""; switch (exp.NodeType) @@ -222,26 +236,29 @@ namespace FreeSql.Extensions.EfCoreFluentApi break; } if (string.IsNullOrEmpty(manyProperty)) throw new ArgumentException("参数错误 many"); - return new HasManyFluent(_tf, manyProperty); + return new HasManyFluent(_fsql, _tf, manyProperty); } public class HasManyFluent { + IFreeSql _fsql; TableFluent _tf; string _selfProperty; string _selfBind; string _withOneProperty; string _withManyProperty; - internal HasManyFluent(TableFluent modelBuilder, string manyProperty) + internal HasManyFluent(IFreeSql fsql, TableFluent modelBuilder, string manyProperty) { + _fsql = fsql; _tf = modelBuilder; _selfProperty = manyProperty; } public void WithMany(Expression>> many, Type middleType) { - if (many?.Body == null) throw new ArgumentException("参数错误 many 不能为 null"); - var exp = many.Body; + var exp = many?.Body; + if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; + if (exp == null) throw new ArgumentException("参数错误 many 不能为 null"); switch (exp.NodeType) { @@ -252,12 +269,13 @@ namespace FreeSql.Extensions.EfCoreFluentApi if (string.IsNullOrEmpty(_withManyProperty)) throw new ArgumentException("参数错误 many"); _tf.Navigate(_selfProperty, null, middleType); - _tf.ConfigEntity(eb2 => eb2.Navigate(_withManyProperty, null, middleType)); + _fsql.CodeFirst.ConfigEntity(eb2 => eb2.Navigate(_withManyProperty, null, middleType)); } public HasManyFluent WithOne(Expression> one) { - if (one?.Body == null) throw new ArgumentException("参数错误 one 不能为 null"); - var exp = one.Body; + var exp = one?.Body; + if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; + if (exp == null) throw new ArgumentException("参数错误 one 不能为 null"); switch (exp.NodeType) { @@ -268,13 +286,14 @@ namespace FreeSql.Extensions.EfCoreFluentApi if (string.IsNullOrEmpty(_withOneProperty)) throw new ArgumentException("参数错误 one"); if (string.IsNullOrEmpty(_selfBind) == false) - _tf.ConfigEntity(eb2 => eb2.Navigate(_withOneProperty, _selfBind)); + _fsql.CodeFirst.ConfigEntity(eb2 => eb2.Navigate(_withOneProperty, _selfBind)); return this; } public HasManyFluent HasForeignKey(Expression> foreignKey) { - if (foreignKey?.Body == null) throw new ArgumentException("参数错误 foreignKey 不能为 null"); - var exp = foreignKey.Body; + var exp = foreignKey?.Body; + if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; + if (exp == null) throw new ArgumentException("参数错误 foreignKey 不能为 null"); switch (exp.NodeType) { @@ -292,7 +311,7 @@ namespace FreeSql.Extensions.EfCoreFluentApi if (string.IsNullOrEmpty(_selfBind)) throw new ArgumentException("参数错误 foreignKey"); _tf.Navigate(_selfProperty, _selfBind); if (string.IsNullOrEmpty(_withOneProperty) == false) - _tf.ConfigEntity(eb2 => eb2.Navigate(_withOneProperty, _selfBind)); + _fsql.CodeFirst.ConfigEntity(eb2 => eb2.Navigate(_withOneProperty, _selfBind)); return this; } } @@ -303,10 +322,40 @@ namespace FreeSql.Extensions.EfCoreFluentApi _tf.Property(property).IsIgnore(true); return this; } - //public EfCoreTableFluent HasData(T data) => HasData(new[] { data }); - //public EfCoreTableFluent HasData(IEnumerable data) - //{ - // return this; - //} + public EfCoreTableFluent HasData(T data) => HasData(new[] { data }); + + /// + /// 使用 Repository + EnableAddOrUpdateNavigateList + NoneParameter 方式插入种子数据 + /// + /// + /// + public EfCoreTableFluent HasData(IEnumerable data) + { + if (data.Any() == false) return this; + var sdCopy = data.Select(a => (object)a).ToList(); + var sdCopyLock = new object(); + _fsql.Aop.SyncStructureAfter += new EventHandler((s, e) => + { + object[] sd = null; + lock (sdCopyLock) + sd = sdCopy?.ToArray(); + if (sd == null || sd.Any() == false) return; + foreach (var et in e.EntityTypes) + { + if (et != typeof(T)) continue; + if (_fsql.Select().AsType(et).Any()) continue; + + var repo = _fsql.GetRepository(); + repo.DbContextOptions.EnableAddOrUpdateNavigateList = true; + repo.DbContextOptions.NoneParameter = true; + repo.AsType(et); + repo.Insert(sd); + + lock (sdCopyLock) + sdCopy = null; + } + }); + return this; + } } } diff --git a/Extensions/FreeSql.Extensions.EfCoreFluentApi/FreeSql.Extensions.EfCoreFluentApi.csproj b/Extensions/FreeSql.Extensions.EfCoreFluentApi/FreeSql.Extensions.EfCoreFluentApi.csproj index b8b85b3a..53b785ab 100644 --- a/Extensions/FreeSql.Extensions.EfCoreFluentApi/FreeSql.Extensions.EfCoreFluentApi.csproj +++ b/Extensions/FreeSql.Extensions.EfCoreFluentApi/FreeSql.Extensions.EfCoreFluentApi.csproj @@ -25,13 +25,13 @@ + + + + FreeSql.Extensions.EfCoreFluentApi.xml 3 - - - - diff --git a/Extensions/FreeSql.Extensions.EfCoreFluentApi/FreeSql.Extensions.EfCoreFluentApi.xml b/Extensions/FreeSql.Extensions.EfCoreFluentApi/FreeSql.Extensions.EfCoreFluentApi.xml index 35afb8c0..55be793f 100644 --- a/Extensions/FreeSql.Extensions.EfCoreFluentApi/FreeSql.Extensions.EfCoreFluentApi.xml +++ b/Extensions/FreeSql.Extensions.EfCoreFluentApi/FreeSql.Extensions.EfCoreFluentApi.xml @@ -4,5 +4,12 @@ FreeSql.Extensions.EfCoreFluentApi + + + 使用 Repository + EnableAddOrUpdateNavigateList + NoneParameter 方式插入种子数据 + + + + diff --git a/Extensions/FreeSql.Extensions.EfCoreFluentApi/ICodeFirstExtensions.cs b/Extensions/FreeSql.Extensions.EfCoreFluentApi/ICodeFirstExtensions.cs index 198f6a3c..542af7c2 100644 --- a/Extensions/FreeSql.Extensions.EfCoreFluentApi/ICodeFirstExtensions.cs +++ b/Extensions/FreeSql.Extensions.EfCoreFluentApi/ICodeFirstExtensions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq.Expressions; using FreeSql.DataAnnotations; +using FreeSql.Internal.CommonProvider; namespace FreeSql.Extensions.EfCoreFluentApi { @@ -10,13 +11,14 @@ namespace FreeSql.Extensions.EfCoreFluentApi public static ICodeFirst Entity(this ICodeFirst codeFirst, Action> modelBuilder) { - codeFirst.ConfigEntity(tf => modelBuilder(new EfCoreTableFluent(tf))); + var cf = codeFirst as CodeFirstProvider; + codeFirst.ConfigEntity(tf => modelBuilder(new EfCoreTableFluent(cf._orm, tf))); return codeFirst; } - static void Test() + public static void Test(IFreeSql fsql) { - ICodeFirst cf = null; + var cf = fsql.CodeFirst; cf.Entity(eb => { eb.ToTable("tb_song"); @@ -25,7 +27,7 @@ namespace FreeSql.Extensions.EfCoreFluentApi eb.Property(a => a.Url).HasMaxLength(100); eb.Property(a => a.RowVersion).IsRowVersion(); - eb.Property(a => a.CreateTime).HasDefaultValueSql("getdate()"); + eb.Property(a => a.CreateTime).HasDefaultValueSql("current_timestamp"); eb.HasKey(a => a.Id); eb.HasIndex(a => a.Title).IsUnique().HasName("idx_xxx11"); @@ -39,7 +41,33 @@ namespace FreeSql.Extensions.EfCoreFluentApi cf.Entity(eb => { eb.HasMany(a => a.Songs).WithOne(a => a.Type).HasForeignKey(a => a.TypeId); + + eb.HasData(new[] + { + new SongType + { + Id = 1, + Name = "流行", + Songs = new List(new[] + { + new Song{ Title = "真的爱你" }, + new Song{ Title = "爱你一万年" }, + }) + }, + new SongType + { + Id = 2, + Name = "乡村", + Songs = new List(new[] + { + new Song{ Title = "乡里乡亲" }, + }) + }, + }); }); + + cf.SyncStructure(); + cf.SyncStructure(); } public class SongType @@ -52,6 +80,7 @@ namespace FreeSql.Extensions.EfCoreFluentApi public class Song { + [Column(IsIdentity = true)] public int Id { get; set; } public string Title { get; set; } public string Url { get; set; } diff --git a/FreeSql.DbContext/DbContext/DbContextOptions.cs b/FreeSql.DbContext/DbContext/DbContextOptions.cs index 8264011a..deb9490e 100644 --- a/FreeSql.DbContext/DbContext/DbContextOptions.cs +++ b/FreeSql.DbContext/DbContext/DbContextOptions.cs @@ -22,6 +22,11 @@ namespace FreeSql /// public bool EnableAddOrUpdateNavigateList { get; set; } = false; + /// + /// 使用无参数化设置(对应 IInsert/IUpdate) + /// + public bool? NoneParameter { get; set; } + /// /// 实体变化事件 /// diff --git a/FreeSql.DbContext/DbSet/DbSet.cs b/FreeSql.DbContext/DbSet/DbSet.cs index 4dbe2715..9dfe6aa2 100644 --- a/FreeSql.DbContext/DbSet/DbSet.cs +++ b/FreeSql.DbContext/DbSet/DbSet.cs @@ -52,11 +52,21 @@ namespace FreeSql } } - protected virtual IInsert OrmInsert() => _db.Orm.Insert().AsType(_entityType).WithTransaction(_uow?.GetOrBeginTransaction()); - protected virtual IInsert OrmInsert(TEntity data) => _db.Orm.Insert().AsType(_entityType).WithTransaction(_uow?.GetOrBeginTransaction()).AppendData(data); - protected virtual IInsert OrmInsert(IEnumerable data) => _db.Orm.Insert().AsType(_entityType).WithTransaction(_uow?.GetOrBeginTransaction()).AppendData(data); + protected virtual IInsert OrmInsert() + { + var insert = _db.Orm.Insert().AsType(_entityType).WithTransaction(_uow?.GetOrBeginTransaction()); + if (_db.Options.NoneParameter != null) insert.NoneParameter(_db.Options.NoneParameter.Value); + return insert; + } + protected virtual IInsert OrmInsert(TEntity data) => OrmInsert().AppendData(data); + protected virtual IInsert OrmInsert(IEnumerable data) => OrmInsert().AppendData(data); - protected virtual IUpdate OrmUpdate(IEnumerable entitys) => _db.Orm.Update().AsType(_entityType).SetSource(entitys).WithTransaction(_uow?.GetOrBeginTransaction()); + protected virtual IUpdate OrmUpdate(IEnumerable entitys) + { + var update = _db.Orm.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); internal void EnqueueToDbContext(DbContext.EntityChangeType changeType, EntityState state) => diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index bd335d0e..3cbd07b4 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -87,6 +87,11 @@ - 属性集合不为空时,与数据库存在的关联数据(中间表)完全对比,计算出应该删除和添加的记录 + + + 使用无参数化设置(对应 IInsert/IUpdate) + + 实体变化事件 diff --git a/FreeSql.DbContext/Repository/ContextSet/RepositoryDbContext.cs b/FreeSql.DbContext/Repository/ContextSet/RepositoryDbContext.cs index 98abccd2..8945b6fa 100644 --- a/FreeSql.DbContext/Repository/ContextSet/RepositoryDbContext.cs +++ b/FreeSql.DbContext/Repository/ContextSet/RepositoryDbContext.cs @@ -33,8 +33,9 @@ namespace FreeSql (repo as IBaseRepository).UnitOfWork = _repo.UnitOfWork; GetRepositoryDbField(entityType).SetValue(repo, this); - typeof(RepositoryDbContext).GetMethod("SetRepositoryDataFilter").MakeGenericMethod(_repo.EntityType) - .Invoke(null, new object[] { repo, _repo }); + if (typeof(IBaseRepository<>).MakeGenericType(_repo.EntityType).IsAssignableFrom(_repo.GetType())) + typeof(RepositoryDbContext).GetMethod("SetRepositoryDataFilter").MakeGenericMethod(_repo.EntityType) + .Invoke(null, new object[] { repo, _repo }); } var sd = Activator.CreateInstance(typeof(RepositoryDbSet<>).MakeGenericType(entityType), repo) as IDbSet; @@ -43,10 +44,10 @@ namespace FreeSql return sd; } - public static void SetRepositoryDataFilter(object repos, BaseRepository baseRepo) where TEntity : class + public static void SetRepositoryDataFilter(object repo, IBaseRepository baseRepo) where TEntity : class { var filter = baseRepo.DataFilter as DataFilter; - DataFilterUtil.SetRepositoryDataFilter(repos, fl => + DataFilterUtil.SetRepositoryDataFilter(repo, fl => { foreach (var f in filter._filters) fl.Apply(f.Key, f.Value.Expression); diff --git a/FreeSql/DataAnnotations/TableFluent.cs b/FreeSql/DataAnnotations/TableFluent.cs index 7c8b66c9..f1e93d42 100644 --- a/FreeSql/DataAnnotations/TableFluent.cs +++ b/FreeSql/DataAnnotations/TableFluent.cs @@ -8,22 +8,17 @@ namespace FreeSql.DataAnnotations { public class TableFluent { - - public TableFluent(ICodeFirst codeFirst, Type entityType, TableAttribute table) + public TableFluent(Type entityType, TableAttribute table) { - _codeFirst = codeFirst; _entityType = entityType; _properties = _entityType.GetPropertiesDictIgnoreCase(); _table = table; } - ICodeFirst _codeFirst; Type _entityType; Dictionary _properties; TableAttribute _table; - public void ConfigEntity(Action> fluent2) => _codeFirst.ConfigEntity(fluent2); - /// /// 数据库表名 /// @@ -89,20 +84,15 @@ namespace FreeSql.DataAnnotations public class TableFluent { - - public TableFluent(ICodeFirst codeFirst, TableAttribute table) + public TableFluent(TableAttribute table) { - _codeFirst = codeFirst; _properties = typeof(T).GetPropertiesDictIgnoreCase(); _table = table; } - ICodeFirst _codeFirst; Dictionary _properties; TableAttribute _table; - public void ConfigEntity(Action> fluent2) => _codeFirst.ConfigEntity(fluent2); - /// /// 数据库表名 /// @@ -131,7 +121,9 @@ namespace FreeSql.DataAnnotations public ColumnFluent Property(Expression> column) { - var proto = (column.Body as MemberExpression)?.Member; + var exp = column?.Body; + if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; + var proto = (exp as MemberExpression)?.Member; if (proto == null) throw new FormatException($"错误的表达式格式 {column}"); return Property(proto.Name); } @@ -152,7 +144,9 @@ namespace FreeSql.DataAnnotations /// public TableFluent Navigate(Expression> proto, string bind, Type manyToMany = null) { - var member = (proto.Body as MemberExpression)?.Member; + var exp = proto?.Body; + if (exp.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand; + var member = (exp as MemberExpression)?.Member; if (member == null) throw new FormatException($"错误的表达式格式 {proto}"); return Navigate(member.Name, bind, manyToMany); } diff --git a/FreeSql/Extensions/FreeSqlGlobalExtensions.cs b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs index 546f8c22..45ce906d 100644 --- a/FreeSql/Extensions/FreeSqlGlobalExtensions.cs +++ b/FreeSql/Extensions/FreeSqlGlobalExtensions.cs @@ -58,6 +58,7 @@ public static partial class FreeSqlGlobalExtensions if (type == null) return null; if (type == typeof(void)) return "void"; if (type.IsGenericParameter) return type.Name; + if (type.IsArray) return $"{DisplayCsharp(type.GetElementType())}[]"; var sb = new StringBuilder(); var nestedType = type; while (nestedType.IsNested) diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index e9379bd3..94b4980f 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -2317,6 +2317,137 @@ + + + 查询,若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】 + + + + + + + + + 查询,ExecuteReaderAsync(dr => {}, "select * from user where age > ?age", new { age = 25 }) + + + + + + + 查询 + + + + + + + 查询,ExecuteArrayAsync("select * from user where age > ?age", new { age = 25 }) + + + + + + + + 查询 + + + + + + + 查询,ExecuteDataSetAsync("select * from user where age > ?age; select 2", new { age = 25 }) + + + + + + + + 查询 + + + + + + + 查询,ExecuteDataTableAsync("select * from user where age > ?age", new { age = 25 }) + + + + + + + + 在【主库】执行 + + + + + + + + 在【主库】执行,ExecuteNonQueryAsync("delete from user where age > ?age", new { age = 25 }) + + + + + + + + 在【主库】执行 + + + + + + + + 在【主库】执行,ExecuteScalarAsync("select 1 from user where age > ?age", new { age = 25 }) + + + + + + + + 执行SQL返回对象集合,QueryAsync<User>("select * from user where age > ?age", new SqlParameter { ParameterName = "age", Value = 25 }) + + + + + + + + + + 执行SQL返回对象集合,QueryAsync<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 }) + + + + + + 可自定义解析表达式 @@ -2840,6 +2971,12 @@ 超时 + + + 获取资源 + + + 使用完毕后,归还资源 @@ -2910,6 +3047,12 @@ 资源对象 + + + 从对象池获取对象成功的时候触发,通过该方法统计或初始化对象 + + 资源对象 + 归还对象给对象池的时候触发 diff --git a/FreeSql/FreeSqlBuilder.cs b/FreeSql/FreeSqlBuilder.cs index 11e881a7..319bed75 100644 --- a/FreeSql/FreeSqlBuilder.cs +++ b/FreeSql/FreeSqlBuilder.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.Concurrent; using System.Data.Common; using System.Linq; using System.Reflection; @@ -308,7 +309,7 @@ namespace FreeSql { ret.Aop.SyncStructureAfter += new EventHandler((s, e) => { - if (string.IsNullOrEmpty(e.Sql)) return; + if (_seedData._data.Any() == false) return; foreach (var et in e.EntityTypes) { if (_seedData._data.TryGetValue(et, out var sd) == false) continue; @@ -320,6 +321,7 @@ namespace FreeSql .InsertIdentity() .AppendData(sd.ToArray()) .ExecuteAffrows(); + _seedData._data.TryRemove(et, out var old); } }); @@ -335,11 +337,11 @@ namespace FreeSql public class SeedDataBuilder { - internal Dictionary> _data = new Dictionary>(); + internal ConcurrentDictionary> _data = new ConcurrentDictionary>(); public SeedDataBuilder Apply(T data) where T : class { if (_data.TryGetValue(typeof(T), out var ds) == false) - _data.Add(typeof(T), ds = new List()); + _data.TryAdd(typeof(T), ds = new List()); ds.Add(data); return this; } diff --git a/FreeSql/Internal/CommonProvider/CodeFirstProvider.cs b/FreeSql/Internal/CommonProvider/CodeFirstProvider.cs index 2e414072..02c38cff 100644 --- a/FreeSql/Internal/CommonProvider/CodeFirstProvider.cs +++ b/FreeSql/Internal/CommonProvider/CodeFirstProvider.cs @@ -17,9 +17,9 @@ namespace FreeSql.Internal.CommonProvider public abstract partial class CodeFirstProvider : ICodeFirst { - protected IFreeSql _orm; - protected CommonUtils _commonUtils; - protected CommonExpression _commonExpression; + public IFreeSql _orm; + public CommonUtils _commonUtils; + public CommonExpression _commonExpression; public CodeFirstProvider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) { _orm = orm; diff --git a/FreeSql/Internal/CommonProvider/InsertProvider.cs b/FreeSql/Internal/CommonProvider/InsertProvider.cs index 161a630b..313434de 100644 --- a/FreeSql/Internal/CommonProvider/InsertProvider.cs +++ b/FreeSql/Internal/CommonProvider/InsertProvider.cs @@ -134,6 +134,8 @@ 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) + throw new Exception($"操作的数据类型({data.GetType().DisplayCsharp()}) 与 AsType({table.Type.DisplayCsharp()}) 不一致,请检查。"); foreach (var col in table.Columns.Values) { object val = col.GetMapValue(data); diff --git a/FreeSql/Internal/CommonProvider/UpdateProvider.cs b/FreeSql/Internal/CommonProvider/UpdateProvider.cs index 6f04aafd..a1a94a38 100644 --- a/FreeSql/Internal/CommonProvider/UpdateProvider.cs +++ b/FreeSql/Internal/CommonProvider/UpdateProvider.cs @@ -351,6 +351,8 @@ namespace FreeSql.Internal.CommonProvider { if (orm.Aop.AuditValueHandler == null) return; if (data == null) return; + if (typeof(T1) == typeof(object) && data.GetType() != table.Type) + throw new Exception($"操作的数据类型({data.GetType().DisplayCsharp()}) 与 AsType({table.Type.DisplayCsharp()}) 不一致,请检查。"); foreach (var col in table.Columns.Values) { object val = col.GetMapValue(data); diff --git a/FreeSql/Internal/CommonUtils.cs b/FreeSql/Internal/CommonUtils.cs index 8a59fe20..9ffab8cb 100644 --- a/FreeSql/Internal/CommonUtils.cs +++ b/FreeSql/Internal/CommonUtils.cs @@ -79,7 +79,7 @@ namespace FreeSql.Internal if (entity == null) return _orm.CodeFirst; var type = typeof(T); var table = dicConfigEntity.GetOrAdd(type, new TableAttribute()); - var fluent = new TableFluent(CodeFirst, table); + var fluent = new TableFluent(table); entity.Invoke(fluent); Utils.RemoveTableByEntity(type, this); //remove cache return _orm.CodeFirst; @@ -88,7 +88,7 @@ namespace FreeSql.Internal { if (entity == null) return _orm.CodeFirst; var table = dicConfigEntity.GetOrAdd(type, new TableAttribute()); - var fluent = new TableFluent(CodeFirst, type, table); + var fluent = new TableFluent(type, table); entity.Invoke(fluent); Utils.RemoveTableByEntity(type, this); //remove cache return _orm.CodeFirst;