2015-03-08 73 views
1

我想使工廠類返回DbContext對象,其中表名將作爲字符串傳遞。數據庫中有超過100個表,每個表具有不同的結構/模式。c#EF DbContext - 從字符串動態生成對象

想法是通過tableName作爲string在將返回對象在EF中的方法,我們可以選擇/更新這些記錄。我在一些文章中發現了這個代碼,但是有一些混淆如何使用它:

public ObjectContext Context(EntityObject entity) 
{ 
     var relationshipManager = ((IEntityWithRelationships)entity).RelationshipManager; 
     var wrappedOwnerProperty = relationshipManager.GetType().GetProperty("WrappedOwner", BindingFlags.Instance | BindingFlags.NonPublic); 
     var wrappedOwner = wrappedOwnerProperty.GetValue(relationshipManager); 
     var contextProperty = wrappedOwner.GetType().GetProperty("Context"); 
     return (ObjectContext)contextProperty.GetValue(wrappedOwner); 
} 

我不確定這是否是我需要的。此外,我應該通過EntityObject entity和我應該通過tableName

請讓我知道是否有任何其他方式來實現相同的事情。

回答

4

一個簡單的方法是使用DbContext.Set()方法,並根據字符串獲取類型。

using (var db = new MyDbContext) 
{ 
    string tableName = "ApplicationUser"; 
    var type = Assembly.GetExecutingAssembly() 
     .GetTypes() 
     .FirstOrDefault(t => t.Name == tableName); 

    if(type != null) 
    DbSet catContext = context.Set(type);  
} 

但是,這有一個缺點,就是這樣,這是一個非通用DbSet(即它是一個DbSet不是DbSet<T>)。

一種方式來獲得通用DbSet(允許LINQ功能)將做這樣的事情:

using (var db = new IdentityDbContext()) 
{ 
    string tableName = "ApplicationUser"; 
    var type = Assembly.GetExecutingAssembly() 
     .GetTypes().FirstOrDefault(t => t.Name == tableName); 

    var method = db.GetType().GetMethods() 
     .First(x => x.IsGenericMethod && x.Name == "Set"); 

    MethodInfo generic = method.MakeGenericMethod(type); 
    var set = generic.Invoke(db, null); 
} 

當然集將在這裏一個對象,你必須以某種方式將其丟,這仍然是問題的一部分。

當它歸結爲它時,如果你不打算使用靜態編譯類型,你將不得不繼續處理反射,特別是當你有通用類型來處理時(例如DbSet<T>,其中之一其他)。您必須讓它們在某個時刻轉換爲靜態類型才能調用方法,或者繼續執行MethodInfo.Invoke。

另一種選擇是使用動態的,但你不能使用C#擴展方法動態(不強制轉換爲具體的類型),所以你回來沒支持LINQ同一條船上。

通過反射使用Linq是一個巨大的痛苦。老實說,如果你有100個類,我只是咬緊牙關,寫硬編碼的類型,或者使用代碼生成器來爲你做CodeSmith。