支持Fluent API .以继承接口的形式配置实体的。

This commit is contained in:
luoyunchong 2021-11-12 01:37:38 +08:00
parent 352ceceb23
commit c88706be3c
5 changed files with 144 additions and 2 deletions

View File

@ -1,3 +1,4 @@
using efcore_to_freesql.Entitys;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System; using System;
@ -14,6 +15,15 @@ namespace efcore_to_freesql.DBContexts
{ {
base.OnModelCreating(modelBuilder); base.OnModelCreating(modelBuilder);
Fsql.CodeFirst.ConfigEntity(modelBuilder.Model); //ͬ²½ÅäÖà Fsql.CodeFirst.ConfigEntity(modelBuilder.Model); //ͬ²½ÅäÖÃ
//配置单个
Fsql.CodeFirst.ApplyConfiguration(new SongConfiguration());
//批量量配置
//Fsql.CodeFirst.ApplyConfigurationsFromAssembly(typeof(SongConfiguration).Assembly);
Fsql.CodeFirst.SyncStructure<Song>();
} }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{ {

View File

@ -1,5 +1,6 @@
using efcore_to_freesql.Entitys; using efcore_to_freesql.Entitys;
using FreeSql; using FreeSql;
using FreeSql.Extensions.EfCoreFluentApi;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Metadata;
using System; using System;
@ -178,4 +179,27 @@ public static class CodeFirstExtensions
cf.SyncStructure<SongType>(); cf.SyncStructure<SongType>();
cf.SyncStructure<Song>(); cf.SyncStructure<Song>();
} }
} }
public class SongConfiguration : FreeSql.Extensions.EfCoreFluentApi.IEntityTypeConfiguration<Song>
{
public void Configure(EfCoreTableFluent<Song> eb)
{
eb.ToTable("tb_song_config");
eb.Ignore(a => a.Field1);
eb.Property(a => a.Title).HasColumnType("varchar(50)").IsRequired();
eb.Property(a => a.Url).HasMaxLength(100);
eb.Property(a => a.RowVersion).IsRowVersion();
eb.Property(a => a.CreateTime).HasDefaultValueSql("current_timestamp");
eb.HasKey(a => a.Id);
eb.HasIndex(a => a.Title).IsUnique().HasName("idx_tb_song1111");
//一对多、多对一
eb.HasOne(a => a.Type).HasForeignKey(a => a.TypeId).WithMany(a => a.Songs);
//多对多
eb.HasMany(a => a.Tags).WithMany(a => a.Songs, typeof(Song_tag));
}
}

View File

@ -28,7 +28,7 @@ namespace efcore_to_freesql
.Build(); .Build();
//Fsql.CodeFirst.EfCoreFluentApiTestGeneric(); //Fsql.CodeFirst.EfCoreFluentApiTestGeneric();
Fsql.CodeFirst.EfCoreFluentApiTestDynamic(); //Fsql.CodeFirst.EfCoreFluentApiTestDynamic();
BaseDBContext.Fsql = Fsql; BaseDBContext.Fsql = Fsql;

View File

@ -1,6 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection;
using FreeSql; using FreeSql;
using FreeSql.DataAnnotations; using FreeSql.DataAnnotations;
using FreeSql.Extensions.EfCoreFluentApi; using FreeSql.Extensions.EfCoreFluentApi;
@ -34,4 +36,103 @@ partial class FreeSqlDbContextExtensions
codeFirst.ConfigEntity(entityType, tf => modelBuilder(new EfCoreTableFluent(cf._orm, tf, entityType))); codeFirst.ConfigEntity(entityType, tf => modelBuilder(new EfCoreTableFluent(cf._orm, tf, entityType)));
return codeFirst; return codeFirst;
} }
public static ICodeFirst ApplyConfiguration<TEntity>(this ICodeFirst codeFirst, IEntityTypeConfiguration<TEntity> configuration) where TEntity : class
{
return codeFirst.Entity<TEntity>(eb =>
{
configuration.Configure(eb);
});
}
#if net40
#else
static IEnumerable<MethodInfo> GetExtensionMethods(this Assembly assembly, Type extendedType)
{
var query = from type in assembly.GetTypes()
where !type.IsGenericType && !type.IsNested
from method in type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
where method.IsDefined(typeof(System.Runtime.CompilerServices.ExtensionAttribute), false)
where method.GetParameters()[0].ParameterType == extendedType
select method;
return query;
}
/// <summary>
/// 根据Assembly扫描所有继承IEntityTypeConfiguration&lt;T&gt;的配置类
/// </summary>
/// <param name="codeFirst"></param>
/// <param name="assembly"></param>
/// <param name="predicate"></param>
/// <returns></returns>
public static ICodeFirst ApplyConfigurationsFromAssembly(this ICodeFirst codeFirst, Assembly assembly, Func<Type, bool> predicate = null)
{
IEnumerable<TypeInfo> typeInfos = assembly.DefinedTypes.Where(t => !t.IsAbstract && !t.IsGenericTypeDefinition);
MethodInfo methodInfo = typeof(FreeSqlDbContextExtensions).Assembly.GetExtensionMethods(typeof(ICodeFirst))
.Single((e) => e.Name == "Entity" && e.ContainsGenericParameters);
if (methodInfo == null) return codeFirst;
foreach (TypeInfo constructibleType in typeInfos)
{
if (constructibleType.GetConstructor(Type.EmptyTypes) == null || predicate != null && !predicate(constructibleType))
{
continue;
}
foreach (var @interface in constructibleType.GetInterfaces())
{
if (@interface.IsGenericType && @interface.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>))
{
var type = @interface.GetGenericArguments().First();
var efFluentType = typeof(EfCoreTableFluent<>).MakeGenericType(type);
var actionType = typeof(Action<>).MakeGenericType(efFluentType);
//1.需要实体和Configuration配置
//codeFirst.Entity<ToDoItem>(eb =>
//{
// new ToDoItemConfiguration().Configure(eb);
//});
//2.需要实体
//Action<EfCoreTableFluent<ToDoItem>> x = new Action<EfCoreTableFluent<ToDoItem>>(e =>
//{
// object o = Activator.CreateInstance(constructibleType);
// constructibleType.GetMethod("ApplyConfiguration")?.Invoke(o, new object[1] { e });
//});
//codeFirst.Entity<ToDoItem>(x);
//3.实现动态调用泛型委托
DelegateBuilder delegateBuilder = new DelegateBuilder(constructibleType);
MethodInfo applyconfigureMethod = delegateBuilder.GetType().GetMethod("ApplyConfiguration")?.MakeGenericMethod(type);
if (applyconfigureMethod == null) continue;
Delegate @delegate = Delegate.CreateDelegate(actionType, delegateBuilder, applyconfigureMethod);
methodInfo.MakeGenericMethod(type).Invoke(null, new object[2]
{
codeFirst,
@delegate
});
}
}
}
return codeFirst;
}
class DelegateBuilder
{
private readonly Type type;
public DelegateBuilder(Type type)
{
this.type = type;
}
public void ApplyConfiguration<T>(EfCoreTableFluent<T> ex)
{
object o = Activator.CreateInstance(type);
type.GetMethod("Configure")?.Invoke(o, new object[1] { ex });
}
}
#endif
} }

View File

@ -0,0 +1,7 @@
namespace FreeSql.Extensions.EfCoreFluentApi
{
public interface IEntityTypeConfiguration<TEntity> where TEntity : class
{
void Configure(EfCoreTableFluent<TEntity> model);
}
}