Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 2 commits into from
May 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Examples/efcore_to_freesql/DBContexts/BaseDBContext.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using efcore_to_freesql.Entitys;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
Expand All @@ -14,6 +15,15 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
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)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using efcore_to_freesql.Entitys;
using FreeSql;
using FreeSql.Extensions.EfCoreFluentApi;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using System;
Expand Down Expand Up @@ -178,4 +179,27 @@ public static void EfCoreFluentApiTestDynamic(this ICodeFirst cf)
cf.SyncStructure<SongType>();
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));
}
}
2 changes: 1 addition & 1 deletion Examples/efcore_to_freesql/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public Startup(IConfiguration configuration, ILoggerFactory loggerFactory)
.Build();

//Fsql.CodeFirst.EfCoreFluentApiTestGeneric();
Fsql.CodeFirst.EfCoreFluentApiTestDynamic();
//Fsql.CodeFirst.EfCoreFluentApiTestDynamic();

BaseDBContext.Fsql = Fsql;

Expand Down
101 changes: 101 additions & 0 deletions FreeSql.DbContext/EfCoreFluentApi/EfCoreFluentApiExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using FreeSql;
using FreeSql.DataAnnotations;
using FreeSql.Extensions.EfCoreFluentApi;
Expand Down Expand Up @@ -34,4 +36,103 @@ public static ICodeFirst Entity(this ICodeFirst codeFirst, Type entityType, Acti
codeFirst.ConfigEntity(entityType, tf => modelBuilder(new EfCoreTableFluent(cf._orm, tf, entityType)));
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
}
7 changes: 7 additions & 0 deletions FreeSql.DbContext/EfCoreFluentApi/IEntityTypeConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace FreeSql.Extensions.EfCoreFluentApi
{
public interface IEntityTypeConfiguration<TEntity> where TEntity : class
{
void Configure(EfCoreTableFluent<TEntity> model);
}
}