mirror of
				https://github.com/nsnail/FreeSql.git
				synced 2025-11-04 17:20:49 +08:00 
			
		
		
		
	- 增加 DbContext 与 EFCore 相似的 FluentApi 对动态类型的处理;#281
This commit is contained in:
		@@ -27,7 +27,8 @@ namespace efcore_to_freesql
 | 
				
			|||||||
                .UseAutoSyncStructure(true)
 | 
					                .UseAutoSyncStructure(true)
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            FreeSqlDbContextExtensions.EfCoreFluentApiTest(Fsql);
 | 
					            //FreeSqlDbContextExtensions.EfCoreFluentApiTestGeneric(Fsql);
 | 
				
			||||||
 | 
					            FreeSqlDbContextExtensions.EfCoreFluentApiTestDynamic(Fsql);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            DBContexts.BaseDBContext.Fsql = Fsql;
 | 
					            DBContexts.BaseDBContext.Fsql = Fsql;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ using FreeSql.Internal.CommonProvider;
 | 
				
			|||||||
partial class FreeSqlDbContextExtensions
 | 
					partial class FreeSqlDbContextExtensions
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// EFCore 99% 相似的 FluentApi 扩展方法
 | 
					    /// EFCore 95% 相似的 FluentApi 扩展方法
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    /// <typeparam name="T"></typeparam>
 | 
					    /// <typeparam name="T"></typeparam>
 | 
				
			||||||
    /// <param name="codeFirst"></param>
 | 
					    /// <param name="codeFirst"></param>
 | 
				
			||||||
@@ -21,13 +21,26 @@ partial class FreeSqlDbContextExtensions
 | 
				
			|||||||
        codeFirst.ConfigEntity<T>(tf => modelBuilder(new EfCoreTableFluent<T>(cf._orm, tf)));
 | 
					        codeFirst.ConfigEntity<T>(tf => modelBuilder(new EfCoreTableFluent<T>(cf._orm, tf)));
 | 
				
			||||||
        return codeFirst;
 | 
					        return codeFirst;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// EFCore 95% 相似的 FluentApi 扩展方法
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="codeFirst"></param>
 | 
				
			||||||
 | 
					    /// <param name="entityType">实体类型</param>
 | 
				
			||||||
 | 
					    /// <param name="modelBuilder"></param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    public static ICodeFirst Entity(this ICodeFirst codeFirst, Type entityType, Action<EfCoreTableFluent> modelBuilder)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var cf = codeFirst as CodeFirstProvider;
 | 
				
			||||||
 | 
					        codeFirst.ConfigEntity(entityType, tf => modelBuilder(new EfCoreTableFluent(cf._orm, tf, entityType)));
 | 
				
			||||||
 | 
					        return codeFirst;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static void EfCoreFluentApiTest(IFreeSql fsql)
 | 
					    public static void EfCoreFluentApiTestGeneric(IFreeSql fsql)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        var cf = fsql.CodeFirst;
 | 
					        var cf = fsql.CodeFirst;
 | 
				
			||||||
        cf.Entity<Song>(eb =>
 | 
					        cf.Entity<Song>(eb =>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            eb.ToTable("tb_song");
 | 
					            eb.ToTable("tb_song1");
 | 
				
			||||||
            eb.Ignore(a => a.Field1);
 | 
					            eb.Ignore(a => a.Field1);
 | 
				
			||||||
            eb.Property(a => a.Title).HasColumnType("varchar(50)").IsRequired();
 | 
					            eb.Property(a => a.Title).HasColumnType("varchar(50)").IsRequired();
 | 
				
			||||||
            eb.Property(a => a.Url).HasMaxLength(100);
 | 
					            eb.Property(a => a.Url).HasMaxLength(100);
 | 
				
			||||||
@@ -36,7 +49,7 @@ partial class FreeSqlDbContextExtensions
 | 
				
			|||||||
            eb.Property(a => a.CreateTime).HasDefaultValueSql("current_timestamp");
 | 
					            eb.Property(a => a.CreateTime).HasDefaultValueSql("current_timestamp");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            eb.HasKey(a => a.Id);
 | 
					            eb.HasKey(a => a.Id);
 | 
				
			||||||
            eb.HasIndex(a => a.Title).IsUnique().HasName("idx_xxx11");
 | 
					            eb.HasIndex(a => a.Title).IsUnique().HasName("idx_tb_song1111");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            //一对多、多对一
 | 
					            //一对多、多对一
 | 
				
			||||||
            eb.HasOne(a => a.Type).HasForeignKey(a => a.TypeId).WithMany(a => a.Songs);
 | 
					            eb.HasOne(a => a.Type).HasForeignKey(a => a.TypeId).WithMany(a => a.Songs);
 | 
				
			||||||
@@ -46,6 +59,7 @@ partial class FreeSqlDbContextExtensions
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
        cf.Entity<SongType>(eb =>
 | 
					        cf.Entity<SongType>(eb =>
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            eb.ToTable("tb_songtype1");
 | 
				
			||||||
            eb.HasMany(a => a.Songs).WithOne(a => a.Type).HasForeignKey(a => a.TypeId);
 | 
					            eb.HasMany(a => a.Songs).WithOne(a => a.Type).HasForeignKey(a => a.TypeId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            eb.HasData(new[]
 | 
					            eb.HasData(new[]
 | 
				
			||||||
@@ -76,6 +90,61 @@ partial class FreeSqlDbContextExtensions
 | 
				
			|||||||
        cf.SyncStructure<Song>();
 | 
					        cf.SyncStructure<Song>();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void EfCoreFluentApiTestDynamic(IFreeSql fsql)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        var cf = fsql.CodeFirst;
 | 
				
			||||||
 | 
					        cf.Entity(typeof(Song), eb =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            eb.ToTable("tb_song2");
 | 
				
			||||||
 | 
					            eb.Ignore("Field1");
 | 
				
			||||||
 | 
					            eb.Property("Title").HasColumnType("varchar(50)").IsRequired();
 | 
				
			||||||
 | 
					            eb.Property("Url").HasMaxLength(100);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            eb.Property("RowVersion").IsRowVersion();
 | 
				
			||||||
 | 
					            eb.Property("CreateTime").HasDefaultValueSql("current_timestamp");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            eb.HasKey("Id");
 | 
				
			||||||
 | 
					            eb.HasIndex("Title").IsUnique().HasName("idx_tb_song2222");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //一对多、多对一
 | 
				
			||||||
 | 
					            eb.HasOne("Type").HasForeignKey("TypeId").WithMany("Songs");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //多对多
 | 
				
			||||||
 | 
					            eb.HasMany("Tags").WithMany("Songs", typeof(Song_tag));
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        cf.Entity(typeof(SongType), eb =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            eb.ToTable("tb_songtype2");
 | 
				
			||||||
 | 
					            eb.HasMany("Songs").WithOne("Type").HasForeignKey("TypeId");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            eb.HasData(new[]
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                new SongType
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Id = 1,
 | 
				
			||||||
 | 
					                    Name = "流行",
 | 
				
			||||||
 | 
					                    Songs = new List<Song>(new[]
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        new Song{ Title = "真的爱你" },
 | 
				
			||||||
 | 
					                        new Song{ Title = "爱你一万年" },
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                new SongType
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    Id = 2,
 | 
				
			||||||
 | 
					                    Name = "乡村",
 | 
				
			||||||
 | 
					                    Songs = new List<Song>(new[]
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        new Song{ Title = "乡里乡亲" },
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cf.SyncStructure<SongType>();
 | 
				
			||||||
 | 
					        cf.SyncStructure<Song>();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public class SongType
 | 
					    public class SongType
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public int Id { get; set; }
 | 
					        public int Id { get; set; }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using System;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Linq;
 | 
					using System.Linq;
 | 
				
			||||||
using System.Linq.Expressions;
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
@@ -6,88 +7,73 @@ using FreeSql.DataAnnotations;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace FreeSql.Extensions.EfCoreFluentApi
 | 
					namespace FreeSql.Extensions.EfCoreFluentApi
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public class EfCoreTableFluent<T>
 | 
					    public class EfCoreTableFluent
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        IFreeSql _fsql;
 | 
					        IFreeSql _fsql;
 | 
				
			||||||
        TableFluent<T> _tf;
 | 
					        TableFluent _tf;
 | 
				
			||||||
        internal EfCoreTableFluent(IFreeSql fsql, TableFluent<T> tf)
 | 
					        internal Type _entityType;
 | 
				
			||||||
 | 
					        internal EfCoreTableFluent(IFreeSql fsql, TableFluent tf, Type entityType)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _fsql = fsql;
 | 
					            _fsql = fsql;
 | 
				
			||||||
            _tf = tf;
 | 
					            _tf = tf;
 | 
				
			||||||
 | 
					            _entityType = entityType;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public EfCoreTableFluent<T> ToTable(string name)
 | 
					        public EfCoreTableFluent ToTable(string name)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _tf.Name(name);
 | 
					            _tf.Name(name);
 | 
				
			||||||
            return this;
 | 
					            return this;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        public EfCoreTableFluent<T> ToView(string name)
 | 
					        public EfCoreTableFluent ToView(string name)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _tf.DisableSyncStructure(true);
 | 
					            _tf.DisableSyncStructure(true);
 | 
				
			||||||
            _tf.Name(name);
 | 
					            _tf.Name(name);
 | 
				
			||||||
            return this;
 | 
					            return this;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public EfCoreColumnFluent Property<TProperty>(Expression<Func<T, TProperty>> property) => new EfCoreColumnFluent(_tf.Property(property));
 | 
					 | 
				
			||||||
        public EfCoreColumnFluent Property(string property) => new EfCoreColumnFluent(_tf.Property(property));
 | 
					        public EfCoreColumnFluent Property(string property) => new EfCoreColumnFluent(_tf.Property(property));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// 使用 FreeSql FluentApi 方法,当 EFCore FluentApi 方法无法表示的时候使用
 | 
					        /// 使用 FreeSql FluentApi 方法,当 EFCore FluentApi 方法无法表示的时候使用
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <returns></returns>
 | 
					        /// <returns></returns>
 | 
				
			||||||
        public TableFluent<T> Help() => _tf;
 | 
					        public TableFluent Help() => _tf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #region HasKey
 | 
					        #region HasKey
 | 
				
			||||||
        public EfCoreTableFluent<T> HasKey(Expression<Func<T, object>> key)
 | 
					        public EfCoreTableFluent HasKey(string key)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var exp = key?.Body;
 | 
					            if (key == null) throw new ArgumentException("参数错误 key 不能为 null");
 | 
				
			||||||
            if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand;
 | 
					            foreach (string name in key.Split(','))
 | 
				
			||||||
            if (exp == null) throw new ArgumentException("参数错误 key 不能为 null");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            switch (exp.NodeType)
 | 
					 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                case ExpressionType.MemberAccess:
 | 
					                if (string.IsNullOrEmpty(name.Trim())) continue;
 | 
				
			||||||
                    _tf.Property((exp as MemberExpression).Member.Name).IsPrimary(true);
 | 
					                _tf.Property(name.Trim()).IsPrimary(true);
 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case ExpressionType.New:
 | 
					 | 
				
			||||||
                    foreach (var member in (exp as NewExpression).Members)
 | 
					 | 
				
			||||||
                        _tf.Property(member.Name).IsPrimary(true);
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return this;
 | 
					            return this;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        #endregion
 | 
					        #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #region HasIndex
 | 
					        #region HasIndex
 | 
				
			||||||
        public HasIndexFluent HasIndex(Expression<Func<T, object>> index)
 | 
					        public HasIndexFluent HasIndex(string index)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var exp = index?.Body;
 | 
					            if (index == null) throw new ArgumentException("参数错误 index 不能为 null");
 | 
				
			||||||
            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 indexName = $"idx_{Guid.NewGuid().ToString("N").Substring(0, 8)}";
 | 
				
			||||||
            var columns = new List<string>();
 | 
					            var columns = new List<string>();
 | 
				
			||||||
            switch (exp.NodeType)
 | 
					            foreach (string name in index.Split(','))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                case ExpressionType.MemberAccess:
 | 
					                if (string.IsNullOrEmpty(name.Trim())) continue;
 | 
				
			||||||
                    columns.Add((exp as MemberExpression).Member.Name);
 | 
					                columns.Add(name.Trim());
 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                case ExpressionType.New:
 | 
					 | 
				
			||||||
                    foreach (var member in (exp as NewExpression).Members)
 | 
					 | 
				
			||||||
                        columns.Add(member.Name);
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            _tf.Index(indexName, string.Join(", ", columns), false);
 | 
					            _tf.Index(indexName, string.Join(", ", columns), false);
 | 
				
			||||||
            return new HasIndexFluent(_tf, indexName, columns);
 | 
					            return new HasIndexFluent(_tf, indexName, columns);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        public class HasIndexFluent
 | 
					        public class HasIndexFluent
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            TableFluent<T> _modelBuilder;
 | 
					            TableFluent _modelBuilder;
 | 
				
			||||||
            string _indexName;
 | 
					            string _indexName;
 | 
				
			||||||
            List<string> _columns;
 | 
					            List<string> _columns;
 | 
				
			||||||
            bool _isUnique;
 | 
					            bool _isUnique;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            internal HasIndexFluent(TableFluent<T> modelBuilder, string indexName, List<string> columns)
 | 
					            internal HasIndexFluent(TableFluent modelBuilder, string indexName, List<string> columns)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                _modelBuilder = modelBuilder;
 | 
					                _modelBuilder = modelBuilder;
 | 
				
			||||||
                _indexName = indexName;
 | 
					                _indexName = indexName;
 | 
				
			||||||
@@ -110,230 +96,157 @@ namespace FreeSql.Extensions.EfCoreFluentApi
 | 
				
			|||||||
        #endregion
 | 
					        #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #region HasOne
 | 
					        #region HasOne
 | 
				
			||||||
        public HasOneFluent<T2> HasOne<T2>(Expression<Func<T, T2>> one)
 | 
					        public HasOneFluent HasOne(string one)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var exp = one?.Body;
 | 
					            if (string.IsNullOrEmpty(one)) throw new ArgumentException("参数错误 one 不能为 null");
 | 
				
			||||||
            if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand;
 | 
					            if (_entityType.GetPropertiesDictIgnoreCase().TryGetValue(one, out var oneProperty) == false) throw new ArgumentException($"参数错误 {one} 属性不存在");
 | 
				
			||||||
            if (exp == null) throw new ArgumentException("参数错误 one 不能为 null");
 | 
					            return new HasOneFluent(_fsql, _tf, _entityType, oneProperty.PropertyType, one);
 | 
				
			||||||
 | 
					 | 
				
			||||||
            var oneProperty = "";
 | 
					 | 
				
			||||||
            switch (exp.NodeType)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                case ExpressionType.MemberAccess:
 | 
					 | 
				
			||||||
                    oneProperty = (exp as MemberExpression).Member.Name;
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
            if (string.IsNullOrEmpty(oneProperty)) throw new ArgumentException("参数错误 one");
 | 
					        public class HasOneFluent
 | 
				
			||||||
            return new HasOneFluent<T2>(_fsql, _tf, oneProperty);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        public class HasOneFluent<T2>
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            IFreeSql _fsql;
 | 
					            IFreeSql _fsql;
 | 
				
			||||||
            TableFluent<T> _tf;
 | 
					            TableFluent _tf;
 | 
				
			||||||
 | 
					            Type _entityType1;
 | 
				
			||||||
 | 
					            Type _entityType2;
 | 
				
			||||||
            string _selfProperty;
 | 
					            string _selfProperty;
 | 
				
			||||||
            string _selfBind;
 | 
					            string _selfBind;
 | 
				
			||||||
            string _withManyProperty;
 | 
					            string _withManyProperty;
 | 
				
			||||||
            string _withOneProperty;
 | 
					            string _withOneProperty;
 | 
				
			||||||
            string _withOneBind;
 | 
					            string _withOneBind;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            internal HasOneFluent(IFreeSql fsql, TableFluent<T> modelBuilder, string oneProperty)
 | 
					            internal HasOneFluent(IFreeSql fsql, TableFluent modelBuilder, Type entityType1, Type entityType2, string oneProperty)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                _fsql = fsql;
 | 
					                _fsql = fsql;
 | 
				
			||||||
                _tf = modelBuilder;
 | 
					                _tf = modelBuilder;
 | 
				
			||||||
 | 
					                _entityType1 = entityType1;
 | 
				
			||||||
 | 
					                _entityType2 = entityType2;
 | 
				
			||||||
                _selfProperty = oneProperty;
 | 
					                _selfProperty = oneProperty;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            public HasOneFluent<T2> WithMany<TMany>(Expression<Func<T2, TMany>> many)
 | 
					            public HasOneFluent WithMany(string many)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var exp = many?.Body;
 | 
					                if (many == null) throw new ArgumentException("参数错误 many 不能为 null");
 | 
				
			||||||
                if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand;
 | 
					                if (_entityType2.GetPropertiesDictIgnoreCase().TryGetValue(many, out var manyProperty) == false) throw new ArgumentException($"参数错误 {many} 属性不存在");
 | 
				
			||||||
                if (exp == null) throw new ArgumentException("参数错误 many 不能为 null");
 | 
					                _withManyProperty = manyProperty.Name;
 | 
				
			||||||
 | 
					 | 
				
			||||||
                switch (exp.NodeType)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    case ExpressionType.MemberAccess:
 | 
					 | 
				
			||||||
                        _withManyProperty = (exp as MemberExpression).Member.Name;
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (string.IsNullOrEmpty(_withManyProperty)) throw new ArgumentException("参数错误 many");
 | 
					 | 
				
			||||||
                if (string.IsNullOrEmpty(_selfBind) == false)
 | 
					                if (string.IsNullOrEmpty(_selfBind) == false)
 | 
				
			||||||
                    _fsql.CodeFirst.ConfigEntity<T2>(eb2 => eb2.Navigate(_withManyProperty, _selfBind));
 | 
					                    _fsql.CodeFirst.ConfigEntity(_entityType2, eb2 => eb2.Navigate(many, _selfBind));
 | 
				
			||||||
                return this;
 | 
					                return this;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            public HasOneFluent<T2> WithOne(Expression<Func<T2, T>> one, Expression<Func<T2, object>> foreignKey)
 | 
					            public HasOneFluent WithOne(string one, string foreignKey)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var exp = one?.Body;
 | 
					                if (string.IsNullOrEmpty(one)) throw new ArgumentException("参数错误 one 不能为 null");
 | 
				
			||||||
                if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand;
 | 
					                if (_entityType1.GetPropertiesDictIgnoreCase().TryGetValue(one, out var oneProperty) == false) throw new ArgumentException($"参数错误 {one} 属性不存在");
 | 
				
			||||||
                if (exp == null) throw new ArgumentException("参数错误 one 不能为 null");
 | 
					                if (oneProperty != _entityType1) throw new ArgumentException($"参数错误 {one} 属性不存在");
 | 
				
			||||||
 | 
					                _withOneProperty = oneProperty.Name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                switch (exp.NodeType)
 | 
					                if (foreignKey == null) throw new ArgumentException("参数错误 foreignKey 不能为 null");
 | 
				
			||||||
 | 
					                foreach (string name in foreignKey.Split(','))
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    case ExpressionType.MemberAccess:
 | 
					                    if (string.IsNullOrEmpty(name.Trim())) continue;
 | 
				
			||||||
                        _withOneProperty = (exp as MemberExpression).Member.Name;
 | 
					                    _withOneBind += ", " + name.Trim();
 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (string.IsNullOrEmpty(_withOneProperty)) throw new ArgumentException("参数错误 one");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                exp = foreignKey?.Body;
 | 
					 | 
				
			||||||
                if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand;
 | 
					 | 
				
			||||||
                if (exp == null) throw new ArgumentException("参数错误 foreignKey 不能为 null");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                switch (exp.NodeType)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    case ExpressionType.MemberAccess:
 | 
					 | 
				
			||||||
                        _withOneBind = (exp as MemberExpression).Member.Name;
 | 
					 | 
				
			||||||
                        _withOneBind = _withOneBind.TrimStart(',', ' ');
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                    case ExpressionType.New:
 | 
					 | 
				
			||||||
                        _withOneBind = "";
 | 
					 | 
				
			||||||
                        foreach (var member in (exp as NewExpression).Members)
 | 
					 | 
				
			||||||
                            _withOneBind += ", " + member.Name;
 | 
					 | 
				
			||||||
                        _withOneBind = _withOneBind.TrimStart(',', ' ');
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                if (string.IsNullOrEmpty(_withOneBind)) throw new ArgumentException("参数错误 foreignKey");
 | 
					                if (string.IsNullOrEmpty(_withOneBind)) throw new ArgumentException("参数错误 foreignKey");
 | 
				
			||||||
 | 
					                _withOneBind = _withOneBind.TrimStart(',', ' ');
 | 
				
			||||||
                if (string.IsNullOrEmpty(_selfBind) == false)
 | 
					                if (string.IsNullOrEmpty(_selfBind) == false)
 | 
				
			||||||
                    _fsql.CodeFirst.ConfigEntity<T2>(eb2 => eb2.Navigate(_withOneProperty, _withOneBind));
 | 
					                    _fsql.CodeFirst.ConfigEntity(_entityType2, eb2 => eb2.Navigate(_withOneProperty, _withOneBind));
 | 
				
			||||||
                return this;
 | 
					                return this;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            public HasOneFluent<T2> HasForeignKey(Expression<Func<T, object>> foreignKey)
 | 
					            public HasOneFluent HasForeignKey(string foreignKey)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var exp = foreignKey?.Body;
 | 
					                if (foreignKey == null) throw new ArgumentException("参数错误 foreignKey 不能为 null");
 | 
				
			||||||
                if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand;
 | 
					                foreach (string name in foreignKey.Split(','))
 | 
				
			||||||
                if (exp == null) throw new ArgumentException("参数错误 foreignKey 不能为 null");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                switch (exp.NodeType)
 | 
					 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    case ExpressionType.MemberAccess:
 | 
					                    if (string.IsNullOrEmpty(name.Trim())) continue;
 | 
				
			||||||
                        _selfBind = (exp as MemberExpression).Member.Name;
 | 
					                    _selfBind += ", " + name.Trim();
 | 
				
			||||||
                        _selfBind = _selfBind.TrimStart(',', ' ');
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                    case ExpressionType.New:
 | 
					 | 
				
			||||||
                        _selfBind = "";
 | 
					 | 
				
			||||||
                        foreach (var member in (exp as NewExpression).Members)
 | 
					 | 
				
			||||||
                            _selfBind += ", " + member.Name;
 | 
					 | 
				
			||||||
                        _selfBind = _selfBind.TrimStart(',', ' ');
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                if (string.IsNullOrEmpty(_selfBind)) throw new ArgumentException("参数错误 foreignKey");
 | 
					                if (string.IsNullOrEmpty(_selfBind)) throw new ArgumentException("参数错误 foreignKey");
 | 
				
			||||||
 | 
					                _selfBind = _selfBind.TrimStart(',', ' ');
 | 
				
			||||||
                _tf.Navigate(_selfProperty, _selfBind);
 | 
					                _tf.Navigate(_selfProperty, _selfBind);
 | 
				
			||||||
                if (string.IsNullOrEmpty(_withManyProperty) == false)
 | 
					                if (string.IsNullOrEmpty(_withManyProperty) == false)
 | 
				
			||||||
                    _fsql.CodeFirst.ConfigEntity<T2>(eb2 => eb2.Navigate(_withManyProperty, _selfBind));
 | 
					                    _fsql.CodeFirst.ConfigEntity(_entityType2, eb2 => eb2.Navigate(_withManyProperty, _selfBind));
 | 
				
			||||||
                if (string.IsNullOrEmpty(_withOneProperty) == false && string.IsNullOrEmpty(_withOneBind) == false)
 | 
					                if (string.IsNullOrEmpty(_withOneProperty) == false && string.IsNullOrEmpty(_withOneBind) == false)
 | 
				
			||||||
                    _fsql.CodeFirst.ConfigEntity<T2>(eb2 => eb2.Navigate(_withOneProperty, _withOneBind));
 | 
					                    _fsql.CodeFirst.ConfigEntity(_entityType2, eb2 => eb2.Navigate(_withOneProperty, _withOneBind));
 | 
				
			||||||
                return this;
 | 
					                return this;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        #endregion
 | 
					        #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #region HasMany
 | 
					        #region HasMany
 | 
				
			||||||
        public HasManyFluent<T2> HasMany<T2>(Expression<Func<T, IEnumerable<T2>>> many)
 | 
					        public HasManyFluent HasMany(string many)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var exp = many?.Body;
 | 
					            if (string.IsNullOrEmpty(many)) throw new ArgumentException("参数错误 many 不能为 null");
 | 
				
			||||||
            if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand;
 | 
					            if (_entityType.GetPropertiesDictIgnoreCase().TryGetValue(many, out var manyProperty) == false) throw new ArgumentException($"参数错误 {many} 集合属性不存在");
 | 
				
			||||||
            if (exp == null) throw new ArgumentException("参数错误 many 不能为 null");
 | 
					            if (typeof(IEnumerable).IsAssignableFrom(manyProperty.PropertyType) == false || manyProperty.PropertyType.IsGenericType == false) throw new ArgumentException("参数错误 {many} 不是集合属性");
 | 
				
			||||||
 | 
					            return new HasManyFluent(_fsql, _tf, _entityType, manyProperty.PropertyType.GetGenericArguments()[0], manyProperty.Name);
 | 
				
			||||||
            var manyProperty = "";
 | 
					 | 
				
			||||||
            switch (exp.NodeType)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                case ExpressionType.MemberAccess:
 | 
					 | 
				
			||||||
                    manyProperty = (exp as MemberExpression).Member.Name;
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
            if (string.IsNullOrEmpty(manyProperty)) throw new ArgumentException("参数错误 many");
 | 
					        public class HasManyFluent
 | 
				
			||||||
            return new HasManyFluent<T2>(_fsql, _tf, manyProperty);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        public class HasManyFluent<T2>
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            IFreeSql _fsql;
 | 
					            IFreeSql _fsql;
 | 
				
			||||||
            TableFluent<T> _tf;
 | 
					            TableFluent _tf;
 | 
				
			||||||
 | 
					            Type _entityType1;
 | 
				
			||||||
 | 
					            Type _entityType2;
 | 
				
			||||||
            string _selfProperty;
 | 
					            string _selfProperty;
 | 
				
			||||||
            string _selfBind;
 | 
					            string _selfBind;
 | 
				
			||||||
            string _withOneProperty;
 | 
					            string _withOneProperty;
 | 
				
			||||||
            string _withManyProperty;
 | 
					            string _withManyProperty;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            internal HasManyFluent(IFreeSql fsql, TableFluent<T> modelBuilder, string manyProperty)
 | 
					            internal HasManyFluent(IFreeSql fsql, TableFluent modelBuilder, Type entityType1, Type entityType2, string manyProperty)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                _fsql = fsql;
 | 
					                _fsql = fsql;
 | 
				
			||||||
                _tf = modelBuilder;
 | 
					                _tf = modelBuilder;
 | 
				
			||||||
 | 
					                _entityType1 = entityType1;
 | 
				
			||||||
 | 
					                _entityType2 = entityType2;
 | 
				
			||||||
                _selfProperty = manyProperty;
 | 
					                _selfProperty = manyProperty;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            public void WithMany(Expression<Func<T2, IEnumerable<T>>> many, Type middleType)
 | 
					            public void WithMany(string many, Type middleType)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var exp = many?.Body;
 | 
					                if (string.IsNullOrEmpty(many)) throw new ArgumentException("参数错误 many 不能为 null");
 | 
				
			||||||
                if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand;
 | 
					                if (_entityType2.GetPropertiesDictIgnoreCase().TryGetValue(many, out var manyProperty) == false) throw new ArgumentException($"参数错误 {many} 集合属性不存在");
 | 
				
			||||||
                if (exp == null) throw new ArgumentException("参数错误 many 不能为 null");
 | 
					                if (typeof(IEnumerable).IsAssignableFrom(manyProperty.PropertyType) == false || manyProperty.PropertyType.IsGenericType == false) throw new ArgumentException("参数错误 {many} 不是集合属性");
 | 
				
			||||||
 | 
					                _withManyProperty = manyProperty.Name;
 | 
				
			||||||
                switch (exp.NodeType)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    case ExpressionType.MemberAccess:
 | 
					 | 
				
			||||||
                        _withManyProperty = (exp as MemberExpression).Member.Name;
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (string.IsNullOrEmpty(_withManyProperty)) throw new ArgumentException("参数错误 many");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                _tf.Navigate(_selfProperty, null, middleType);
 | 
					                _tf.Navigate(_selfProperty, null, middleType);
 | 
				
			||||||
                _fsql.CodeFirst.ConfigEntity<T2>(eb2 => eb2.Navigate(_withManyProperty, null, middleType));
 | 
					                _fsql.CodeFirst.ConfigEntity(_entityType2, eb2 => eb2.Navigate(_withManyProperty, null, middleType));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            public HasManyFluent<T2> WithOne(Expression<Func<T2, T>> one)
 | 
					            public HasManyFluent WithOne(string one)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var exp = one?.Body;
 | 
					                if (string.IsNullOrEmpty(one)) throw new ArgumentException("参数错误 one 不能为 null");
 | 
				
			||||||
                if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand;
 | 
					                if (_entityType2.GetPropertiesDictIgnoreCase().TryGetValue(one, out var oneProperty) == false) throw new ArgumentException($"参数错误 {one} 属性不存在");
 | 
				
			||||||
                if (exp == null) throw new ArgumentException("参数错误 one 不能为 null");
 | 
					                if (oneProperty.PropertyType != _entityType1) throw new ArgumentException($"参数错误 {one} 属性不存在");
 | 
				
			||||||
 | 
					                _withOneProperty = oneProperty.Name;
 | 
				
			||||||
                switch (exp.NodeType)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    case ExpressionType.MemberAccess:
 | 
					 | 
				
			||||||
                        _withOneProperty = (exp as MemberExpression).Member.Name;
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (string.IsNullOrEmpty(_withOneProperty)) throw new ArgumentException("参数错误 one");
 | 
					 | 
				
			||||||
                
 | 
					 | 
				
			||||||
                if (string.IsNullOrEmpty(_selfBind) == false)
 | 
					                if (string.IsNullOrEmpty(_selfBind) == false)
 | 
				
			||||||
                    _fsql.CodeFirst.ConfigEntity<T2>(eb2 => eb2.Navigate(_withOneProperty, _selfBind));
 | 
					                    _fsql.CodeFirst.ConfigEntity(_entityType2, eb2 => eb2.Navigate(oneProperty.Name, _selfBind));
 | 
				
			||||||
                return this;
 | 
					                return this;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            public HasManyFluent<T2> HasForeignKey(Expression<Func<T2, object>> foreignKey)
 | 
					            public HasManyFluent HasForeignKey(string foreignKey)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var exp = foreignKey?.Body;
 | 
					                if (foreignKey == null) throw new ArgumentException("参数错误 foreignKey 不能为 null");
 | 
				
			||||||
                if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand;
 | 
					                foreach (string name in foreignKey.Split(','))
 | 
				
			||||||
                if (exp == null) throw new ArgumentException("参数错误 foreignKey 不能为 null");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                switch (exp.NodeType)
 | 
					 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    case ExpressionType.MemberAccess:
 | 
					                    if (string.IsNullOrEmpty(name.Trim())) continue;
 | 
				
			||||||
                        _selfBind = (exp as MemberExpression).Member.Name;
 | 
					                    _selfBind += ", " + name.Trim();
 | 
				
			||||||
                        _selfBind = _selfBind.TrimStart(',', ' ');
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                    case ExpressionType.New:
 | 
					 | 
				
			||||||
                        _selfBind = "";
 | 
					 | 
				
			||||||
                        foreach (var member in (exp as NewExpression).Members)
 | 
					 | 
				
			||||||
                            _selfBind += ", " + member.Name;
 | 
					 | 
				
			||||||
                        _selfBind = _selfBind.TrimStart(',', ' ');
 | 
					 | 
				
			||||||
                        break;
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                if (string.IsNullOrEmpty(_selfBind)) throw new ArgumentException("参数错误 foreignKey");
 | 
					                if (string.IsNullOrEmpty(_selfBind)) throw new ArgumentException("参数错误 foreignKey");
 | 
				
			||||||
 | 
					                _selfBind = _selfBind.TrimStart(',', ' ');
 | 
				
			||||||
                _tf.Navigate(_selfProperty, _selfBind);
 | 
					                _tf.Navigate(_selfProperty, _selfBind);
 | 
				
			||||||
                if (string.IsNullOrEmpty(_withOneProperty) == false)
 | 
					                if (string.IsNullOrEmpty(_withOneProperty) == false)
 | 
				
			||||||
                    _fsql.CodeFirst.ConfigEntity<T2>(eb2 => eb2.Navigate(_withOneProperty, _selfBind));
 | 
					                    _fsql.CodeFirst.ConfigEntity(_entityType2, eb2 => eb2.Navigate(_withOneProperty, _selfBind));
 | 
				
			||||||
                return this;
 | 
					                return this;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        #endregion
 | 
					        #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public EfCoreTableFluent<T> Ignore<TProperty>(Expression<Func<T, TProperty>> property)
 | 
					        public EfCoreTableFluent Ignore(string property)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _tf.Property(property).IsIgnore(true);
 | 
					            _tf.Property(property).IsIgnore(true);
 | 
				
			||||||
            return this;
 | 
					            return this;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        public EfCoreTableFluent<T> HasData(T data) => HasData(new[] { data });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// 使用 Repository + EnableAddOrUpdateNavigateList + NoneParameter 方式插入种子数据
 | 
					        /// 使用 Repository + EnableAddOrUpdateNavigateList + NoneParameter 方式插入种子数据
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <param name="data"></param>
 | 
					        /// <param name="data"></param>
 | 
				
			||||||
        /// <returns></returns>
 | 
					        /// <returns></returns>
 | 
				
			||||||
        public EfCoreTableFluent<T> HasData(IEnumerable<T> data)
 | 
					        public EfCoreTableFluent HasData(IEnumerable<object> data)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (data.Any() == false) return this;
 | 
					            if (data.Any() == false) return this;
 | 
				
			||||||
            var sdCopy = data.Select(a => (object)a).ToList();
 | 
					            var sdCopy = data.Select(a => (object)a).ToList();
 | 
				
			||||||
@@ -346,7 +259,7 @@ namespace FreeSql.Extensions.EfCoreFluentApi
 | 
				
			|||||||
                if (sd == null || sd.Any() == false) return;
 | 
					                if (sd == null || sd.Any() == false) return;
 | 
				
			||||||
                foreach (var et in e.EntityTypes)
 | 
					                foreach (var et in e.EntityTypes)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    if (et != typeof(T)) continue;
 | 
					                    if (et != _entityType) continue;
 | 
				
			||||||
                    if (_fsql.Select<object>().AsType(et).Any()) continue;
 | 
					                    if (_fsql.Select<object>().AsType(et).Any()) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    var repo = _fsql.GetRepository<object>();
 | 
					                    var repo = _fsql.GetRepository<object>();
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										365
									
								
								FreeSql.DbContext/EfCoreFluentApi/EfCoreTableFluent`1.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										365
									
								
								FreeSql.DbContext/EfCoreFluentApi/EfCoreTableFluent`1.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,365 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Linq.Expressions;
 | 
				
			||||||
 | 
					using FreeSql.DataAnnotations;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace FreeSql.Extensions.EfCoreFluentApi
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public class EfCoreTableFluent<T>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IFreeSql _fsql;
 | 
				
			||||||
 | 
					        TableFluent<T> _tf;
 | 
				
			||||||
 | 
					        internal EfCoreTableFluent(IFreeSql fsql, TableFluent<T> tf)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _fsql = fsql;
 | 
				
			||||||
 | 
					            _tf = tf;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public EfCoreTableFluent<T> ToTable(string name)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _tf.Name(name);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public EfCoreTableFluent<T> ToView(string name)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _tf.DisableSyncStructure(true);
 | 
				
			||||||
 | 
					            _tf.Name(name);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public EfCoreColumnFluent Property<TProperty>(Expression<Func<T, TProperty>> property) => new EfCoreColumnFluent(_tf.Property(property));
 | 
				
			||||||
 | 
					        public EfCoreColumnFluent Property(string property) => new EfCoreColumnFluent(_tf.Property(property));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 使用 FreeSql FluentApi 方法,当 EFCore FluentApi 方法无法表示的时候使用
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <returns></returns>
 | 
				
			||||||
 | 
					        public TableFluent<T> Help() => _tf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #region HasKey
 | 
				
			||||||
 | 
					        public EfCoreTableFluent<T> HasKey(Expression<Func<T, object>> key)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            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:
 | 
				
			||||||
 | 
					                    _tf.Property((exp as MemberExpression).Member.Name).IsPrimary(true);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case ExpressionType.New:
 | 
				
			||||||
 | 
					                    foreach (var member in (exp as NewExpression).Members)
 | 
				
			||||||
 | 
					                        _tf.Property(member.Name).IsPrimary(true);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #region HasIndex
 | 
				
			||||||
 | 
					        public HasIndexFluent HasIndex(Expression<Func<T, object>> index)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            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<string>();
 | 
				
			||||||
 | 
					            switch (exp.NodeType)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case ExpressionType.MemberAccess:
 | 
				
			||||||
 | 
					                    columns.Add((exp as MemberExpression).Member.Name);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case ExpressionType.New:
 | 
				
			||||||
 | 
					                    foreach (var member in (exp as NewExpression).Members)
 | 
				
			||||||
 | 
					                        columns.Add(member.Name);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            _tf.Index(indexName, string.Join(", ", columns), false);
 | 
				
			||||||
 | 
					            return new HasIndexFluent(_tf, indexName, columns);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public class HasIndexFluent
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            TableFluent<T> _modelBuilder;
 | 
				
			||||||
 | 
					            string _indexName;
 | 
				
			||||||
 | 
					            List<string> _columns;
 | 
				
			||||||
 | 
					            bool _isUnique;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            internal HasIndexFluent(TableFluent<T> modelBuilder, string indexName, List<string> columns)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _modelBuilder = modelBuilder;
 | 
				
			||||||
 | 
					                _indexName = indexName;
 | 
				
			||||||
 | 
					                _columns = columns;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            public HasIndexFluent IsUnique()
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _isUnique = true;
 | 
				
			||||||
 | 
					                _modelBuilder.Index(_indexName, string.Join(", ", _columns), _isUnique);
 | 
				
			||||||
 | 
					                return this;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            public HasIndexFluent HasName(string name)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _modelBuilder.IndexRemove(_indexName);
 | 
				
			||||||
 | 
					                _indexName = name;
 | 
				
			||||||
 | 
					                _modelBuilder.Index(_indexName, string.Join(", ", _columns), _isUnique);
 | 
				
			||||||
 | 
					                return this;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #region HasOne
 | 
				
			||||||
 | 
					        public HasOneFluent<T2> HasOne<T2>(Expression<Func<T, T2>> one)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            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)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case ExpressionType.MemberAccess:
 | 
				
			||||||
 | 
					                    oneProperty = (exp as MemberExpression).Member.Name;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (string.IsNullOrEmpty(oneProperty)) throw new ArgumentException("参数错误 one");
 | 
				
			||||||
 | 
					            return new HasOneFluent<T2>(_fsql, _tf, oneProperty);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public class HasOneFluent<T2>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            IFreeSql _fsql;
 | 
				
			||||||
 | 
					            TableFluent<T> _tf;
 | 
				
			||||||
 | 
					            string _selfProperty;
 | 
				
			||||||
 | 
					            string _selfBind;
 | 
				
			||||||
 | 
					            string _withManyProperty;
 | 
				
			||||||
 | 
					            string _withOneProperty;
 | 
				
			||||||
 | 
					            string _withOneBind;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            internal HasOneFluent(IFreeSql fsql, TableFluent<T> modelBuilder, string oneProperty)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _fsql = fsql;
 | 
				
			||||||
 | 
					                _tf = modelBuilder;
 | 
				
			||||||
 | 
					                _selfProperty = oneProperty;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            public HasOneFluent<T2> WithMany<TMany>(Expression<Func<T2, TMany>> many)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                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)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case ExpressionType.MemberAccess:
 | 
				
			||||||
 | 
					                        _withManyProperty = (exp as MemberExpression).Member.Name;
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(_withManyProperty)) throw new ArgumentException("参数错误 many");
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(_selfBind) == false)
 | 
				
			||||||
 | 
					                    _fsql.CodeFirst.ConfigEntity<T2>(eb2 => eb2.Navigate(_withManyProperty, _selfBind));
 | 
				
			||||||
 | 
					                return this;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            public HasOneFluent<T2> WithOne(Expression<Func<T2, T>> one, Expression<Func<T2, object>> foreignKey)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                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)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case ExpressionType.MemberAccess:
 | 
				
			||||||
 | 
					                        _withOneProperty = (exp as MemberExpression).Member.Name;
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(_withOneProperty)) throw new ArgumentException("参数错误 one");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                exp = foreignKey?.Body;
 | 
				
			||||||
 | 
					                if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand;
 | 
				
			||||||
 | 
					                if (exp == null) throw new ArgumentException("参数错误 foreignKey 不能为 null");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                switch (exp.NodeType)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case ExpressionType.MemberAccess:
 | 
				
			||||||
 | 
					                        _withOneBind = (exp as MemberExpression).Member.Name;
 | 
				
			||||||
 | 
					                        _withOneBind = _withOneBind.TrimStart(',', ' ');
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    case ExpressionType.New:
 | 
				
			||||||
 | 
					                        _withOneBind = "";
 | 
				
			||||||
 | 
					                        foreach (var member in (exp as NewExpression).Members)
 | 
				
			||||||
 | 
					                            _withOneBind += ", " + member.Name;
 | 
				
			||||||
 | 
					                        _withOneBind = _withOneBind.TrimStart(',', ' ');
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(_withOneBind)) throw new ArgumentException("参数错误 foreignKey");
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(_selfBind) == false)
 | 
				
			||||||
 | 
					                    _fsql.CodeFirst.ConfigEntity<T2>(eb2 => eb2.Navigate(_withOneProperty, _withOneBind));
 | 
				
			||||||
 | 
					                return this;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            public HasOneFluent<T2> HasForeignKey(Expression<Func<T, object>> foreignKey)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                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)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case ExpressionType.MemberAccess:
 | 
				
			||||||
 | 
					                        _selfBind = (exp as MemberExpression).Member.Name;
 | 
				
			||||||
 | 
					                        _selfBind = _selfBind.TrimStart(',', ' ');
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    case ExpressionType.New:
 | 
				
			||||||
 | 
					                        _selfBind = "";
 | 
				
			||||||
 | 
					                        foreach (var member in (exp as NewExpression).Members)
 | 
				
			||||||
 | 
					                            _selfBind += ", " + member.Name;
 | 
				
			||||||
 | 
					                        _selfBind = _selfBind.TrimStart(',', ' ');
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(_selfBind)) throw new ArgumentException("参数错误 foreignKey");
 | 
				
			||||||
 | 
					                _tf.Navigate(_selfProperty, _selfBind);
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(_withManyProperty) == false)
 | 
				
			||||||
 | 
					                    _fsql.CodeFirst.ConfigEntity<T2>(eb2 => eb2.Navigate(_withManyProperty, _selfBind));
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(_withOneProperty) == false && string.IsNullOrEmpty(_withOneBind) == false)
 | 
				
			||||||
 | 
					                    _fsql.CodeFirst.ConfigEntity<T2>(eb2 => eb2.Navigate(_withOneProperty, _withOneBind));
 | 
				
			||||||
 | 
					                return this;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #region HasMany
 | 
				
			||||||
 | 
					        public HasManyFluent<T2> HasMany<T2>(Expression<Func<T, IEnumerable<T2>>> many)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            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)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case ExpressionType.MemberAccess:
 | 
				
			||||||
 | 
					                    manyProperty = (exp as MemberExpression).Member.Name;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (string.IsNullOrEmpty(manyProperty)) throw new ArgumentException("参数错误 many");
 | 
				
			||||||
 | 
					            return new HasManyFluent<T2>(_fsql, _tf, manyProperty);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public class HasManyFluent<T2>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            IFreeSql _fsql;
 | 
				
			||||||
 | 
					            TableFluent<T> _tf;
 | 
				
			||||||
 | 
					            string _selfProperty;
 | 
				
			||||||
 | 
					            string _selfBind;
 | 
				
			||||||
 | 
					            string _withOneProperty;
 | 
				
			||||||
 | 
					            string _withManyProperty;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            internal HasManyFluent(IFreeSql fsql, TableFluent<T> modelBuilder, string manyProperty)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _fsql = fsql;
 | 
				
			||||||
 | 
					                _tf = modelBuilder;
 | 
				
			||||||
 | 
					                _selfProperty = manyProperty;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            public void WithMany(Expression<Func<T2, IEnumerable<T>>> many, Type middleType)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                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)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case ExpressionType.MemberAccess:
 | 
				
			||||||
 | 
					                        _withManyProperty = (exp as MemberExpression).Member.Name;
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(_withManyProperty)) throw new ArgumentException("参数错误 many");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                _tf.Navigate(_selfProperty, null, middleType);
 | 
				
			||||||
 | 
					                _fsql.CodeFirst.ConfigEntity<T2>(eb2 => eb2.Navigate(_withManyProperty, null, middleType));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            public HasManyFluent<T2> WithOne(Expression<Func<T2, T>> one)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                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)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case ExpressionType.MemberAccess:
 | 
				
			||||||
 | 
					                        _withOneProperty = (exp as MemberExpression).Member.Name;
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(_withOneProperty)) throw new ArgumentException("参数错误 one");
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(_selfBind) == false)
 | 
				
			||||||
 | 
					                    _fsql.CodeFirst.ConfigEntity<T2>(eb2 => eb2.Navigate(_withOneProperty, _selfBind));
 | 
				
			||||||
 | 
					                return this;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            public HasManyFluent<T2> HasForeignKey(Expression<Func<T2, object>> foreignKey)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                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)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    case ExpressionType.MemberAccess:
 | 
				
			||||||
 | 
					                        _selfBind = (exp as MemberExpression).Member.Name;
 | 
				
			||||||
 | 
					                        _selfBind = _selfBind.TrimStart(',', ' ');
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    case ExpressionType.New:
 | 
				
			||||||
 | 
					                        _selfBind = "";
 | 
				
			||||||
 | 
					                        foreach (var member in (exp as NewExpression).Members)
 | 
				
			||||||
 | 
					                            _selfBind += ", " + member.Name;
 | 
				
			||||||
 | 
					                        _selfBind = _selfBind.TrimStart(',', ' ');
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(_selfBind)) throw new ArgumentException("参数错误 foreignKey");
 | 
				
			||||||
 | 
					                _tf.Navigate(_selfProperty, _selfBind);
 | 
				
			||||||
 | 
					                if (string.IsNullOrEmpty(_withOneProperty) == false)
 | 
				
			||||||
 | 
					                    _fsql.CodeFirst.ConfigEntity<T2>(eb2 => eb2.Navigate(_withOneProperty, _selfBind));
 | 
				
			||||||
 | 
					                return this;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public EfCoreTableFluent<T> Ignore<TProperty>(Expression<Func<T, TProperty>> property)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _tf.Property(property).IsIgnore(true);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        public EfCoreTableFluent<T> HasData(T data) => HasData(new[] { data });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        /// 使用 Repository + EnableAddOrUpdateNavigateList + NoneParameter 方式插入种子数据
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        /// <param name="data"></param>
 | 
				
			||||||
 | 
					        /// <returns></returns>
 | 
				
			||||||
 | 
					        public EfCoreTableFluent<T> HasData(IEnumerable<T> data)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (data.Any() == false) return this;
 | 
				
			||||||
 | 
					            var sdCopy = data.Select(a => (object)a).ToList();
 | 
				
			||||||
 | 
					            var sdCopyLock = new object();
 | 
				
			||||||
 | 
					            _fsql.Aop.SyncStructureAfter += new EventHandler<Aop.SyncStructureAfterEventArgs>((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<object>().AsType(et).Any()) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var repo = _fsql.GetRepository<object>();
 | 
				
			||||||
 | 
					                    repo.DbContextOptions.EnableAddOrUpdateNavigateList = true;
 | 
				
			||||||
 | 
					                    repo.DbContextOptions.NoneParameter = true;
 | 
				
			||||||
 | 
					                    repo.AsType(et);
 | 
				
			||||||
 | 
					                    repo.Insert(sd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    lock (sdCopyLock)
 | 
				
			||||||
 | 
					                        sdCopy = null;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -175,6 +175,19 @@
 | 
				
			|||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.Extensions.EfCoreFluentApi.EfCoreTableFluent.Help">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            使用 FreeSql FluentApi 方法,当 EFCore FluentApi 方法无法表示的时候使用
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.Extensions.EfCoreFluentApi.EfCoreTableFluent.HasData(System.Collections.Generic.IEnumerable{System.Object})">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            使用 Repository + EnableAddOrUpdateNavigateList + NoneParameter 方式插入种子数据
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="data"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
        <member name="M:FreeSql.Extensions.EfCoreFluentApi.EfCoreTableFluent`1.Help">
 | 
					        <member name="M:FreeSql.Extensions.EfCoreFluentApi.EfCoreTableFluent`1.Help">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            使用 FreeSql FluentApi 方法,当 EFCore FluentApi 方法无法表示的时候使用
 | 
					            使用 FreeSql FluentApi 方法,当 EFCore FluentApi 方法无法表示的时候使用
 | 
				
			||||||
@@ -330,13 +343,22 @@
 | 
				
			|||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:FreeSqlDbContextExtensions.Entity``1(FreeSql.ICodeFirst,System.Action{FreeSql.Extensions.EfCoreFluentApi.EfCoreTableFluent{``0}})">
 | 
					        <member name="M:FreeSqlDbContextExtensions.Entity``1(FreeSql.ICodeFirst,System.Action{FreeSql.Extensions.EfCoreFluentApi.EfCoreTableFluent{``0}})">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            EFCore 99% 相似的 FluentApi 扩展方法
 | 
					            EFCore 95% 相似的 FluentApi 扩展方法
 | 
				
			||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <typeparam name="T"></typeparam>
 | 
					            <typeparam name="T"></typeparam>
 | 
				
			||||||
            <param name="codeFirst"></param>
 | 
					            <param name="codeFirst"></param>
 | 
				
			||||||
            <param name="modelBuilder"></param>
 | 
					            <param name="modelBuilder"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSqlDbContextExtensions.Entity(FreeSql.ICodeFirst,System.Type,System.Action{FreeSql.Extensions.EfCoreFluentApi.EfCoreTableFluent})">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            EFCore 95% 相似的 FluentApi 扩展方法
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="codeFirst"></param>
 | 
				
			||||||
 | 
					            <param name="entityType">实体类型</param>
 | 
				
			||||||
 | 
					            <param name="modelBuilder"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
        <member name="M:FreeSqlDbContextExtensions.CreateDbContext(IFreeSql)">
 | 
					        <member name="M:FreeSqlDbContextExtensions.CreateDbContext(IFreeSql)">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            创建普通数据上下文档对象
 | 
					            创建普通数据上下文档对象
 | 
				
			||||||
@@ -395,14 +417,5 @@
 | 
				
			|||||||
            <param name="that"></param>
 | 
					            <param name="that"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
        <member name="M:Microsoft.Extensions.DependencyInjection.FreeSqlRepositoryDependencyInjection.AddFreeRepository(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Action{FreeSql.FluentDataFilter},System.Reflection.Assembly[])">
 | 
					 | 
				
			||||||
            <summary>
 | 
					 | 
				
			||||||
            批量注入 Repository,可以参考代码自行调整
 | 
					 | 
				
			||||||
            </summary>
 | 
					 | 
				
			||||||
            <param name="services"></param>
 | 
					 | 
				
			||||||
            <param name="globalDataFilter"></param>
 | 
					 | 
				
			||||||
            <param name="assemblies"></param>
 | 
					 | 
				
			||||||
            <returns></returns>
 | 
					 | 
				
			||||||
        </member>
 | 
					 | 
				
			||||||
    </members>
 | 
					    </members>
 | 
				
			||||||
</doc>
 | 
					</doc>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -80,6 +80,11 @@ namespace FreeSql.DataAnnotations
 | 
				
			|||||||
            _table._indexs.AddOrUpdate(name, idx, (_, __) => idx);
 | 
					            _table._indexs.AddOrUpdate(name, idx, (_, __) => idx);
 | 
				
			||||||
            return this;
 | 
					            return this;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        public TableFluent IndexRemove(string name)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _table._indexs.TryRemove(name, out var oldidx);
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public class TableFluent<T>
 | 
					    public class TableFluent<T>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2305,6 +2305,137 @@
 | 
				
			|||||||
            <param name="parms"></param>
 | 
					            <param name="parms"></param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IAdo.ExecuteReaderAsync(System.Func{System.Data.Common.DbDataReader,System.Threading.Tasks.Task},System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            查询,若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="readerHander"></param>
 | 
				
			||||||
 | 
					            <param name="cmdType"></param>
 | 
				
			||||||
 | 
					            <param name="cmdText"></param>
 | 
				
			||||||
 | 
					            <param name="cmdParms"></param>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IAdo.ExecuteReaderAsync(System.Func{System.Data.Common.DbDataReader,System.Threading.Tasks.Task},System.String,System.Object)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            查询,ExecuteReaderAsync(dr => {}, "select * from user where age > ?age", new { age = 25 })
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="cmdText"></param>
 | 
				
			||||||
 | 
					            <param name="parms"></param>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IAdo.ExecuteArrayAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            查询
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="cmdText"></param>
 | 
				
			||||||
 | 
					            <param name="cmdParms"></param>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IAdo.ExecuteArrayAsync(System.String,System.Object)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            查询,ExecuteArrayAsync("select * from user where age > ?age", new { age = 25 })
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="cmdText"></param>
 | 
				
			||||||
 | 
					            <param name="parms"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IAdo.ExecuteDataSetAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            查询
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="cmdText"></param>
 | 
				
			||||||
 | 
					            <param name="cmdParms"></param>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IAdo.ExecuteDataSetAsync(System.String,System.Object)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            查询,ExecuteDataSetAsync("select * from user where age > ?age; select 2", new { age = 25 })
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="cmdText"></param>
 | 
				
			||||||
 | 
					            <param name="parms"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IAdo.ExecuteDataTableAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            查询
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="cmdText"></param>
 | 
				
			||||||
 | 
					            <param name="cmdParms"></param>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IAdo.ExecuteDataTableAsync(System.String,System.Object)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            查询,ExecuteDataTableAsync("select * from user where age > ?age", new { age = 25 })
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="cmdText"></param>
 | 
				
			||||||
 | 
					            <param name="parms"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IAdo.ExecuteNonQueryAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            在【主库】执行
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="cmdType"></param>
 | 
				
			||||||
 | 
					            <param name="cmdText"></param>
 | 
				
			||||||
 | 
					            <param name="cmdParms"></param>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IAdo.ExecuteNonQueryAsync(System.String,System.Object)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            在【主库】执行,ExecuteNonQueryAsync("delete from user where age > ?age", new { age = 25 })
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="cmdText"></param>
 | 
				
			||||||
 | 
					            <param name="parms"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IAdo.ExecuteScalarAsync(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            在【主库】执行
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="cmdType"></param>
 | 
				
			||||||
 | 
					            <param name="cmdText"></param>
 | 
				
			||||||
 | 
					            <param name="cmdParms"></param>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IAdo.ExecuteScalarAsync(System.String,System.Object)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            在【主库】执行,ExecuteScalarAsync("select 1 from user where age > ?age", new { age = 25 })
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="cmdText"></param>
 | 
				
			||||||
 | 
					            <param name="parms"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IAdo.QueryAsync``1(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            执行SQL返回对象集合,QueryAsync<User>("select * from user where age > ?age", new SqlParameter { ParameterName = "age", Value = 25 })
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <typeparam name="T"></typeparam>
 | 
				
			||||||
 | 
					            <param name="cmdType"></param>
 | 
				
			||||||
 | 
					            <param name="cmdText"></param>
 | 
				
			||||||
 | 
					            <param name="cmdParms"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IAdo.QueryAsync``1(System.String,System.Object)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            执行SQL返回对象集合,QueryAsync<User>("select * from user where age > ?age", new { age = 25 })
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <typeparam name="T"></typeparam>
 | 
				
			||||||
 | 
					            <param name="cmdText"></param>
 | 
				
			||||||
 | 
					            <param name="parms"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IAdo.QueryAsync``2(System.Data.CommandType,System.String,System.Data.Common.DbParameter[])">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            执行SQL返回对象集合,Query<User>("select * from user where age > ?age; select * from address", new SqlParameter { ParameterName = "age", Value = 25 })
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <typeparam name="T1"></typeparam>
 | 
				
			||||||
 | 
					            <param name="cmdType"></param>
 | 
				
			||||||
 | 
					            <param name="cmdText"></param>
 | 
				
			||||||
 | 
					            <param name="cmdParms"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.IAdo.QueryAsync``2(System.String,System.Object)">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            执行SQL返回对象集合,Query<User>("select * from user where age > ?age; select * from address", new { age = 25 })
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <typeparam name="T1"></typeparam>
 | 
				
			||||||
 | 
					            <param name="cmdText"></param>
 | 
				
			||||||
 | 
					            <param name="parms"></param>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
        <member name="E:FreeSql.IAop.ParseExpression">
 | 
					        <member name="E:FreeSql.IAop.ParseExpression">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            可自定义解析表达式
 | 
					            可自定义解析表达式
 | 
				
			||||||
@@ -2825,6 +2956,12 @@
 | 
				
			|||||||
            <param name="timeout">超时</param>
 | 
					            <param name="timeout">超时</param>
 | 
				
			||||||
            <returns></returns>
 | 
					            <returns></returns>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.Internal.ObjectPool.IObjectPool`1.GetAsync">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            获取资源
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <returns></returns>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
        <member name="M:FreeSql.Internal.ObjectPool.IObjectPool`1.Return(FreeSql.Internal.ObjectPool.Object{`0},System.Boolean)">
 | 
					        <member name="M:FreeSql.Internal.ObjectPool.IObjectPool`1.Return(FreeSql.Internal.ObjectPool.Object{`0},System.Boolean)">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            使用完毕后,归还资源
 | 
					            使用完毕后,归还资源
 | 
				
			||||||
@@ -2895,6 +3032,12 @@
 | 
				
			|||||||
            </summary>
 | 
					            </summary>
 | 
				
			||||||
            <param name="obj">资源对象</param>
 | 
					            <param name="obj">资源对象</param>
 | 
				
			||||||
        </member>
 | 
					        </member>
 | 
				
			||||||
 | 
					        <member name="M:FreeSql.Internal.ObjectPool.IPolicy`1.OnGetAsync(FreeSql.Internal.ObjectPool.Object{`0})">
 | 
				
			||||||
 | 
					            <summary>
 | 
				
			||||||
 | 
					            从对象池获取对象成功的时候触发,通过该方法统计或初始化对象
 | 
				
			||||||
 | 
					            </summary>
 | 
				
			||||||
 | 
					            <param name="obj">资源对象</param>
 | 
				
			||||||
 | 
					        </member>
 | 
				
			||||||
        <member name="M:FreeSql.Internal.ObjectPool.IPolicy`1.OnReturn(FreeSql.Internal.ObjectPool.Object{`0})">
 | 
					        <member name="M:FreeSql.Internal.ObjectPool.IPolicy`1.OnReturn(FreeSql.Internal.ObjectPool.Object{`0})">
 | 
				
			||||||
            <summary>
 | 
					            <summary>
 | 
				
			||||||
            归还对象给对象池的时候触发
 | 
					            归还对象给对象池的时候触发
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user