Skip to content

Commit a1f029a

Browse files
authored
Merge pull request #937 from luoyunchong/dev
支持Fluent API .以继承接口的形式配置实体的。
2 parents 7ae936c + 1080363 commit a1f029a

File tree

5 files changed

+144
-2
lines changed

5 files changed

+144
-2
lines changed

Examples/efcore_to_freesql/DBContexts/BaseDBContext.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using efcore_to_freesql.Entitys;
12
using Microsoft.EntityFrameworkCore;
23
using Microsoft.Extensions.Logging;
34
using System;
@@ -14,6 +15,15 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
1415
{
1516
base.OnModelCreating(modelBuilder);
1617
Fsql.CodeFirst.ConfigEntity(modelBuilder.Model); //同步配置
18+
19+
//配置单个
20+
Fsql.CodeFirst.ApplyConfiguration(new SongConfiguration());
21+
22+
//批量量配置
23+
//Fsql.CodeFirst.ApplyConfigurationsFromAssembly(typeof(SongConfiguration).Assembly);
24+
25+
Fsql.CodeFirst.SyncStructure<Song>();
26+
1727
}
1828
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
1929
{

Examples/efcore_to_freesql/FreeSqlExtensions/CodeFirstExtensions.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using efcore_to_freesql.Entitys;
22
using FreeSql;
3+
using FreeSql.Extensions.EfCoreFluentApi;
34
using Microsoft.EntityFrameworkCore;
45
using Microsoft.EntityFrameworkCore.Metadata;
56
using System;
@@ -178,4 +179,27 @@ public static void EfCoreFluentApiTestDynamic(this ICodeFirst cf)
178179
cf.SyncStructure<SongType>();
179180
cf.SyncStructure<Song>();
180181
}
181-
}
182+
}
183+
184+
public class SongConfiguration : FreeSql.Extensions.EfCoreFluentApi.IEntityTypeConfiguration<Song>
185+
{
186+
public void Configure(EfCoreTableFluent<Song> eb)
187+
{
188+
eb.ToTable("tb_song_config");
189+
eb.Ignore(a => a.Field1);
190+
eb.Property(a => a.Title).HasColumnType("varchar(50)").IsRequired();
191+
eb.Property(a => a.Url).HasMaxLength(100);
192+
193+
eb.Property(a => a.RowVersion).IsRowVersion();
194+
eb.Property(a => a.CreateTime).HasDefaultValueSql("current_timestamp");
195+
196+
eb.HasKey(a => a.Id);
197+
eb.HasIndex(a => a.Title).IsUnique().HasName("idx_tb_song1111");
198+
199+
//一对多、多对一
200+
eb.HasOne(a => a.Type).HasForeignKey(a => a.TypeId).WithMany(a => a.Songs);
201+
202+
//多对多
203+
eb.HasMany(a => a.Tags).WithMany(a => a.Songs, typeof(Song_tag));
204+
}
205+
}

Examples/efcore_to_freesql/Startup.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public Startup(IConfiguration configuration, ILoggerFactory loggerFactory)
2828
.Build();
2929

3030
//Fsql.CodeFirst.EfCoreFluentApiTestGeneric();
31-
Fsql.CodeFirst.EfCoreFluentApiTestDynamic();
31+
//Fsql.CodeFirst.EfCoreFluentApiTestDynamic();
3232

3333
BaseDBContext.Fsql = Fsql;
3434

FreeSql.DbContext/EfCoreFluentApi/EfCoreFluentApiExtensions.cs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Linq;
34
using System.Linq.Expressions;
5+
using System.Reflection;
46
using FreeSql;
57
using FreeSql.DataAnnotations;
68
using FreeSql.Extensions.EfCoreFluentApi;
@@ -34,4 +36,103 @@ public static ICodeFirst Entity(this ICodeFirst codeFirst, Type entityType, Acti
3436
codeFirst.ConfigEntity(entityType, tf => modelBuilder(new EfCoreTableFluent(cf._orm, tf, entityType)));
3537
return codeFirst;
3638
}
39+
40+
public static ICodeFirst ApplyConfiguration<TEntity>(this ICodeFirst codeFirst, IEntityTypeConfiguration<TEntity> configuration) where TEntity : class
41+
{
42+
return codeFirst.Entity<TEntity>(eb =>
43+
{
44+
configuration.Configure(eb);
45+
});
46+
}
47+
#if net40
48+
#else
49+
static IEnumerable<MethodInfo> GetExtensionMethods(this Assembly assembly, Type extendedType)
50+
{
51+
var query = from type in assembly.GetTypes()
52+
where !type.IsGenericType && !type.IsNested
53+
from method in type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
54+
where method.IsDefined(typeof(System.Runtime.CompilerServices.ExtensionAttribute), false)
55+
where method.GetParameters()[0].ParameterType == extendedType
56+
select method;
57+
return query;
58+
}
59+
60+
/// <summary>
61+
/// 根据Assembly扫描所有继承IEntityTypeConfiguration&lt;T&gt;的配置类
62+
/// </summary>
63+
/// <param name="codeFirst"></param>
64+
/// <param name="assembly"></param>
65+
/// <param name="predicate"></param>
66+
/// <returns></returns>
67+
public static ICodeFirst ApplyConfigurationsFromAssembly(this ICodeFirst codeFirst, Assembly assembly, Func<Type, bool> predicate = null)
68+
{
69+
IEnumerable<TypeInfo> typeInfos = assembly.DefinedTypes.Where(t => !t.IsAbstract && !t.IsGenericTypeDefinition);
70+
71+
MethodInfo methodInfo = typeof(FreeSqlDbContextExtensions).Assembly.GetExtensionMethods(typeof(ICodeFirst))
72+
.Single((e) => e.Name == "Entity" && e.ContainsGenericParameters);
73+
74+
if (methodInfo == null) return codeFirst;
75+
76+
foreach (TypeInfo constructibleType in typeInfos)
77+
{
78+
if (constructibleType.GetConstructor(Type.EmptyTypes) == null || predicate != null && !predicate(constructibleType))
79+
{
80+
continue;
81+
}
82+
83+
foreach (var @interface in constructibleType.GetInterfaces())
84+
{
85+
if (@interface.IsGenericType && @interface.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>))
86+
{
87+
var type = @interface.GetGenericArguments().First();
88+
var efFluentType = typeof(EfCoreTableFluent<>).MakeGenericType(type);
89+
var actionType = typeof(Action<>).MakeGenericType(efFluentType);
90+
91+
//1.需要实体和Configuration配置
92+
//codeFirst.Entity<ToDoItem>(eb =>
93+
//{
94+
// new ToDoItemConfiguration().Configure(eb);
95+
//});
96+
97+
//2.需要实体
98+
//Action<EfCoreTableFluent<ToDoItem>> x = new Action<EfCoreTableFluent<ToDoItem>>(e =>
99+
//{
100+
// object o = Activator.CreateInstance(constructibleType);
101+
// constructibleType.GetMethod("ApplyConfiguration")?.Invoke(o, new object[1] { e });
102+
//});
103+
//codeFirst.Entity<ToDoItem>(x);
104+
105+
//3.实现动态调用泛型委托
106+
DelegateBuilder delegateBuilder = new DelegateBuilder(constructibleType);
107+
MethodInfo applyconfigureMethod = delegateBuilder.GetType().GetMethod("ApplyConfiguration")?.MakeGenericMethod(type);
108+
if (applyconfigureMethod == null) continue;
109+
Delegate @delegate = Delegate.CreateDelegate(actionType, delegateBuilder, applyconfigureMethod);
110+
111+
methodInfo.MakeGenericMethod(type).Invoke(null, new object[2]
112+
{
113+
codeFirst,
114+
@delegate
115+
});
116+
117+
}
118+
}
119+
}
120+
121+
return codeFirst;
122+
}
123+
class DelegateBuilder
124+
{
125+
private readonly Type type;
126+
127+
public DelegateBuilder(Type type)
128+
{
129+
this.type = type;
130+
}
131+
public void ApplyConfiguration<T>(EfCoreTableFluent<T> ex)
132+
{
133+
object o = Activator.CreateInstance(type);
134+
type.GetMethod("Configure")?.Invoke(o, new object[1] { ex });
135+
}
136+
}
137+
#endif
37138
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace FreeSql.Extensions.EfCoreFluentApi
2+
{
3+
public interface IEntityTypeConfiguration<TEntity> where TEntity : class
4+
{
5+
void Configure(EfCoreTableFluent<TEntity> model);
6+
}
7+
}

0 commit comments

Comments
 (0)