diff --git a/Examples/efcore_to_freesql/Startup.cs b/Examples/efcore_to_freesql/Startup.cs
index 2271d74f..0245f0c9 100644
--- a/Examples/efcore_to_freesql/Startup.cs
+++ b/Examples/efcore_to_freesql/Startup.cs
@@ -27,7 +27,8 @@ namespace efcore_to_freesql
.UseAutoSyncStructure(true)
.Build();
- FreeSqlDbContextExtensions.EfCoreFluentApiTest(Fsql);
+ //FreeSqlDbContextExtensions.EfCoreFluentApiTestGeneric(Fsql);
+ FreeSqlDbContextExtensions.EfCoreFluentApiTestDynamic(Fsql);
DBContexts.BaseDBContext.Fsql = Fsql;
diff --git a/FreeSql.DbContext/EfCoreFluentApi/EfCoreFluentApiExtensions.cs b/FreeSql.DbContext/EfCoreFluentApi/EfCoreFluentApiExtensions.cs
index 30661258..e31ac3fe 100644
--- a/FreeSql.DbContext/EfCoreFluentApi/EfCoreFluentApiExtensions.cs
+++ b/FreeSql.DbContext/EfCoreFluentApi/EfCoreFluentApiExtensions.cs
@@ -9,7 +9,7 @@ using FreeSql.Internal.CommonProvider;
partial class FreeSqlDbContextExtensions
{
///
- /// EFCore 99% 相似的 FluentApi 扩展方法
+ /// EFCore 95% 相似的 FluentApi 扩展方法
///
///
///
@@ -21,13 +21,26 @@ partial class FreeSqlDbContextExtensions
codeFirst.ConfigEntity(tf => modelBuilder(new EfCoreTableFluent(cf._orm, tf)));
return codeFirst;
}
+ ///
+ /// EFCore 95% 相似的 FluentApi 扩展方法
+ ///
+ ///
+ /// 实体类型
+ ///
+ ///
+ public static ICodeFirst Entity(this ICodeFirst codeFirst, Type entityType, Action 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;
cf.Entity(eb =>
{
- eb.ToTable("tb_song");
+ eb.ToTable("tb_song1");
eb.Ignore(a => a.Field1);
eb.Property(a => a.Title).HasColumnType("varchar(50)").IsRequired();
eb.Property(a => a.Url).HasMaxLength(100);
@@ -36,7 +49,7 @@ partial class FreeSqlDbContextExtensions
eb.Property(a => a.CreateTime).HasDefaultValueSql("current_timestamp");
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);
@@ -46,6 +59,7 @@ partial class FreeSqlDbContextExtensions
});
cf.Entity(eb =>
{
+ eb.ToTable("tb_songtype1");
eb.HasMany(a => a.Songs).WithOne(a => a.Type).HasForeignKey(a => a.TypeId);
eb.HasData(new[]
@@ -76,6 +90,61 @@ partial class FreeSqlDbContextExtensions
cf.SyncStructure();
}
+ 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(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
{
public int Id { get; set; }
diff --git a/FreeSql.DbContext/EfCoreFluentApi/EfCoreTableFluent.cs b/FreeSql.DbContext/EfCoreFluentApi/EfCoreTableFluent.cs
index 388e7198..90200d24 100644
--- a/FreeSql.DbContext/EfCoreFluentApi/EfCoreTableFluent.cs
+++ b/FreeSql.DbContext/EfCoreFluentApi/EfCoreTableFluent.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
@@ -6,88 +7,73 @@ using FreeSql.DataAnnotations;
namespace FreeSql.Extensions.EfCoreFluentApi
{
- public class EfCoreTableFluent
+ public class EfCoreTableFluent
{
IFreeSql _fsql;
- TableFluent _tf;
- internal EfCoreTableFluent(IFreeSql fsql, TableFluent tf)
+ TableFluent _tf;
+ internal Type _entityType;
+ internal EfCoreTableFluent(IFreeSql fsql, TableFluent tf, Type entityType)
{
_fsql = fsql;
_tf = tf;
+ _entityType = entityType;
}
- public EfCoreTableFluent ToTable(string name)
+ public EfCoreTableFluent ToTable(string name)
{
_tf.Name(name);
return this;
}
- public EfCoreTableFluent ToView(string name)
+ public EfCoreTableFluent ToView(string name)
{
_tf.DisableSyncStructure(true);
_tf.Name(name);
return this;
}
- public EfCoreColumnFluent Property(Expression> property) => new EfCoreColumnFluent(_tf.Property(property));
public EfCoreColumnFluent Property(string property) => new EfCoreColumnFluent(_tf.Property(property));
///
/// 使用 FreeSql FluentApi 方法,当 EFCore FluentApi 方法无法表示的时候使用
///
///
- public TableFluent Help() => _tf;
+ public TableFluent Help() => _tf;
#region HasKey
- public EfCoreTableFluent HasKey(Expression> key)
+ public EfCoreTableFluent HasKey(string 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)
+ if (key == null) throw new ArgumentException("参数错误 key 不能为 null");
+ foreach (string name in key.Split(','))
{
- 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;
+ if (string.IsNullOrEmpty(name.Trim())) continue;
+ _tf.Property(name.Trim()).IsPrimary(true);
}
return this;
}
#endregion
#region HasIndex
- public HasIndexFluent HasIndex(Expression> index)
+ public HasIndexFluent HasIndex(string index)
{
- var exp = index?.Body;
- if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand;
- if (exp == null) throw new ArgumentException("参数错误 index 不能为 null");
-
+ if (index == null) throw new ArgumentException("参数错误 index 不能为 null");
var indexName = $"idx_{Guid.NewGuid().ToString("N").Substring(0, 8)}";
var columns = new List();
- switch (exp.NodeType)
+ foreach (string name in index.Split(','))
{
- 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;
+ if (string.IsNullOrEmpty(name.Trim())) continue;
+ columns.Add(name.Trim());
}
_tf.Index(indexName, string.Join(", ", columns), false);
return new HasIndexFluent(_tf, indexName, columns);
}
public class HasIndexFluent
{
- TableFluent _modelBuilder;
+ TableFluent _modelBuilder;
string _indexName;
List _columns;
bool _isUnique;
- internal HasIndexFluent(TableFluent modelBuilder, string indexName, List columns)
+ internal HasIndexFluent(TableFluent modelBuilder, string indexName, List columns)
{
_modelBuilder = modelBuilder;
_indexName = indexName;
@@ -110,230 +96,157 @@ namespace FreeSql.Extensions.EfCoreFluentApi
#endregion
#region HasOne
- public HasOneFluent HasOne(Expression> one)
+ public HasOneFluent HasOne(string 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(_fsql, _tf, oneProperty);
+ if (string.IsNullOrEmpty(one)) throw new ArgumentException("参数错误 one 不能为 null");
+ if (_entityType.GetPropertiesDictIgnoreCase().TryGetValue(one, out var oneProperty) == false) throw new ArgumentException($"参数错误 {one} 属性不存在");
+ return new HasOneFluent(_fsql, _tf, _entityType, oneProperty.PropertyType, one);
}
- public class HasOneFluent
+ public class HasOneFluent
{
IFreeSql _fsql;
- TableFluent _tf;
+ TableFluent _tf;
+ Type _entityType1;
+ Type _entityType2;
string _selfProperty;
string _selfBind;
string _withManyProperty;
string _withOneProperty;
string _withOneBind;
- internal HasOneFluent(IFreeSql fsql, TableFluent modelBuilder, string oneProperty)
+ internal HasOneFluent(IFreeSql fsql, TableFluent modelBuilder, Type entityType1, Type entityType2, string oneProperty)
{
_fsql = fsql;
_tf = modelBuilder;
+ _entityType1 = entityType1;
+ _entityType2 = entityType2;
_selfProperty = oneProperty;
}
- public HasOneFluent WithMany(Expression> many)
+ public HasOneFluent WithMany(string 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 (many == null) throw new ArgumentException("参数错误 many 不能为 null");
+ if (_entityType2.GetPropertiesDictIgnoreCase().TryGetValue(many, out var manyProperty) == false) throw new ArgumentException($"参数错误 {many} 属性不存在");
+ _withManyProperty = manyProperty.Name;
if (string.IsNullOrEmpty(_selfBind) == false)
- _fsql.CodeFirst.ConfigEntity(eb2 => eb2.Navigate(_withManyProperty, _selfBind));
+ _fsql.CodeFirst.ConfigEntity(_entityType2, eb2 => eb2.Navigate(many, _selfBind));
return this;
}
- public HasOneFluent WithOne(Expression> one, Expression> foreignKey)
+ public HasOneFluent WithOne(string one, string foreignKey)
{
- var exp = one?.Body;
- if (exp?.NodeType == ExpressionType.Convert) exp = (exp as UnaryExpression)?.Operand;
- if (exp == null) throw new ArgumentException("参数错误 one 不能为 null");
+ if (string.IsNullOrEmpty(one)) throw new ArgumentException("参数错误 one 不能为 null");
+ if (_entityType1.GetPropertiesDictIgnoreCase().TryGetValue(one, out var oneProperty) == false) throw new ArgumentException($"参数错误 {one} 属性不存在");
+ 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:
- _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(name.Trim())) continue;
+ _withOneBind += ", " + name.Trim();
}
if (string.IsNullOrEmpty(_withOneBind)) throw new ArgumentException("参数错误 foreignKey");
+ _withOneBind = _withOneBind.TrimStart(',', ' ');
if (string.IsNullOrEmpty(_selfBind) == false)
- _fsql.CodeFirst.ConfigEntity(eb2 => eb2.Navigate(_withOneProperty, _withOneBind));
+ _fsql.CodeFirst.ConfigEntity(_entityType2, eb2 => eb2.Navigate(_withOneProperty, _withOneBind));
return this;
}
- public HasOneFluent HasForeignKey(Expression> foreignKey)
+ public HasOneFluent HasForeignKey(string 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)
+ if (foreignKey == null) throw new ArgumentException("参数错误 foreignKey 不能为 null");
+ foreach (string name in foreignKey.Split(','))
{
- 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(name.Trim())) continue;
+ _selfBind += ", " + name.Trim();
}
if (string.IsNullOrEmpty(_selfBind)) throw new ArgumentException("参数错误 foreignKey");
+ _selfBind = _selfBind.TrimStart(',', ' ');
_tf.Navigate(_selfProperty, _selfBind);
if (string.IsNullOrEmpty(_withManyProperty) == false)
- _fsql.CodeFirst.ConfigEntity(eb2 => eb2.Navigate(_withManyProperty, _selfBind));
+ _fsql.CodeFirst.ConfigEntity(_entityType2, eb2 => eb2.Navigate(_withManyProperty, _selfBind));
if (string.IsNullOrEmpty(_withOneProperty) == false && string.IsNullOrEmpty(_withOneBind) == false)
- _fsql.CodeFirst.ConfigEntity(eb2 => eb2.Navigate(_withOneProperty, _withOneBind));
+ _fsql.CodeFirst.ConfigEntity(_entityType2, eb2 => eb2.Navigate(_withOneProperty, _withOneBind));
return this;
}
}
#endregion
#region HasMany
- public HasManyFluent HasMany(Expression>> many)
+ public HasManyFluent HasMany(string 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(_fsql, _tf, manyProperty);
+ if (string.IsNullOrEmpty(many)) throw new ArgumentException("参数错误 many 不能为 null");
+ if (_entityType.GetPropertiesDictIgnoreCase().TryGetValue(many, out var manyProperty) == false) throw new ArgumentException($"参数错误 {many} 集合属性不存在");
+ 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);
}
- public class HasManyFluent
+ public class HasManyFluent
{
IFreeSql _fsql;
- TableFluent _tf;
+ TableFluent _tf;
+ Type _entityType1;
+ Type _entityType2;
string _selfProperty;
string _selfBind;
string _withOneProperty;
string _withManyProperty;
- internal HasManyFluent(IFreeSql fsql, TableFluent modelBuilder, string manyProperty)
+ internal HasManyFluent(IFreeSql fsql, TableFluent modelBuilder, Type entityType1, Type entityType2, string manyProperty)
{
_fsql = fsql;
_tf = modelBuilder;
+ _entityType1 = entityType1;
+ _entityType2 = entityType2;
_selfProperty = manyProperty;
}
- public void WithMany(Expression>> many, Type middleType)
+ public void WithMany(string 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");
-
+ if (string.IsNullOrEmpty(many)) throw new ArgumentException("参数错误 many 不能为 null");
+ if (_entityType2.GetPropertiesDictIgnoreCase().TryGetValue(many, out var manyProperty) == false) throw new ArgumentException($"参数错误 {many} 集合属性不存在");
+ if (typeof(IEnumerable).IsAssignableFrom(manyProperty.PropertyType) == false || manyProperty.PropertyType.IsGenericType == false) throw new ArgumentException("参数错误 {many} 不是集合属性");
+ _withManyProperty = manyProperty.Name;
_tf.Navigate(_selfProperty, null, middleType);
- _fsql.CodeFirst.ConfigEntity(eb2 => eb2.Navigate(_withManyProperty, null, middleType));
+ _fsql.CodeFirst.ConfigEntity(_entityType2, eb2 => eb2.Navigate(_withManyProperty, null, middleType));
}
- public HasManyFluent WithOne(Expression> one)
+ public HasManyFluent WithOne(string 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(one)) throw new ArgumentException("参数错误 one 不能为 null");
+ if (_entityType2.GetPropertiesDictIgnoreCase().TryGetValue(one, out var oneProperty) == false) throw new ArgumentException($"参数错误 {one} 属性不存在");
+ if (oneProperty.PropertyType != _entityType1) throw new ArgumentException($"参数错误 {one} 属性不存在");
+ _withOneProperty = oneProperty.Name;
if (string.IsNullOrEmpty(_selfBind) == false)
- _fsql.CodeFirst.ConfigEntity(eb2 => eb2.Navigate(_withOneProperty, _selfBind));
+ _fsql.CodeFirst.ConfigEntity(_entityType2, eb2 => eb2.Navigate(oneProperty.Name, _selfBind));
return this;
}
- public HasManyFluent HasForeignKey(Expression> foreignKey)
+ public HasManyFluent HasForeignKey(string 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)
+ if (foreignKey == null) throw new ArgumentException("参数错误 foreignKey 不能为 null");
+ foreach (string name in foreignKey.Split(','))
{
- 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(name.Trim())) continue;
+ _selfBind += ", " + name.Trim();
}
if (string.IsNullOrEmpty(_selfBind)) throw new ArgumentException("参数错误 foreignKey");
+ _selfBind = _selfBind.TrimStart(',', ' ');
_tf.Navigate(_selfProperty, _selfBind);
if (string.IsNullOrEmpty(_withOneProperty) == false)
- _fsql.CodeFirst.ConfigEntity(eb2 => eb2.Navigate(_withOneProperty, _selfBind));
+ _fsql.CodeFirst.ConfigEntity(_entityType2, eb2 => eb2.Navigate(_withOneProperty, _selfBind));
return this;
}
}
#endregion
- public EfCoreTableFluent Ignore(Expression> property)
+ public EfCoreTableFluent Ignore(string property)
{
_tf.Property(property).IsIgnore(true);
return this;
}
- public EfCoreTableFluent HasData(T data) => HasData(new[] { data });
///
/// 使用 Repository + EnableAddOrUpdateNavigateList + NoneParameter 方式插入种子数据
///
///
///
- public EfCoreTableFluent HasData(IEnumerable data)
+ public EfCoreTableFluent HasData(IEnumerable