EF CORE使用反射實現動態DbSet


為什么要動態配置DbSet?

在各種EF CORE的教程中我們可看到,配置DbContext數據庫上下文的模型時都是手寫具體的實體類名來添加

例如手動寫DbSet:
public DbSet<Blog> Blogs { get; set; }

或者在OnModelCreating中進行配置

protected override void OnModelCreating(ModelBuilder modelBuilder) 
{
	modelBuilder.Entity<Blog>() 
		.Property(b => b.Url) 
		.IsRequired(); 
}

但這只適用於實體類比較少的情況下,如果業務量很大,用到幾十上百張表,這樣去配置DbContext就比較麻煩了(其實是太懶了)

實現

具體實現其實很簡單,我們需要反射調用ModelBuilder.Entity方法的重載ModelBuilder.Entity<TEntity>(),看看MS DOC里它的描述:

Entity<TEntity>()
返回一個對象,該對象可用於配置模型中給定的實體類型。 如果實體類型不是模型的一部分,則會將其添加到模型中。

正常我們在OnModelCreating調用該方法時是需要寫明泛型類的,但是為了動態生成DbSet這樣去寫顯然是不現實的,那么就需要通過反射來實現

首先,我們需要建一個專門存放實體類型的項目,或者你也可以放在現有的項目中,這里我假裝有個叫 Model 的類庫項目

然后創建一個實體類

namespace Model
{
    [Table("Blog")]
    public class Blog
    {
    }
}

這里用Table這個Attribute來標識這個類是一個實體類,方便后面反射獲取以及自定義表名,當然你也可以自定義Attribute或者接口來標識

當我們的程序引用了Model項目后就可以在運行時通過AppDomain來獲取程序集中定義的類信息,當然你也可以通過Assembly.LoadFile()來手動指定程序集的路徑進行加載

var definedTypes =
    AppDomain.CurrentDomain.GetAssemblies()
        .FirstOrDefault(s => s.GetName().Name=="Model")
        .DefinedTypes
        .ToList();

然后我們可以通過獲取接口或者Attribute的信息來過濾得到的類信息以免加載不需要的類

var entityTypes = definedTypes
	    .Where(o => o.GetCustomAttributes<Table>().Any())
        .Where(o => o.IsClass && !o.IsAbstract && !o.IsGenericType)
        .ToList();

下面通過反射獲取Entity方法
var entityMethod = typeof(ModelBuilder).GetMethod("Entity", new Type[] { });

然后循環實體類信息集合,反射調用Entity方法生成實體

if (entityTypes is { Count: > 0 })
{
    foreach (var type in entityTypes)
    {
        var entityBuilder = entityMethod
                .MakeGenericMethod(type)
                .Invoke(modelBuilder, new object[] { });
        var hasKeyMethod = entityBuilder.GetType().GetMethod("HasKey", new Type[] { typeof(string[]) });
        hasKeyMethod.Invoke(entityBuilder, new object[] { new string[] { "UID" } });
	}
}

這里還通過HasKey方法設定了主鍵,否則使用時會出現問題。EF CORE默認會把類名作為實體的表名,如果想自定義表名可以通過TableAttribute獲取自定義的表名然后反射調用ToTable方法來設定

然后就可以通過DbContext.Set<T>()來獲取DbSet<T>進行數據庫操作了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM