2017-05-05 82 views
0

背景使用的PropertyInfo爲泛型類型時調用一個泛型方法

我使用的是EF,我有許多表。當我插入一個帶有導航屬性'內容但沒有id的新實體時(我正在從xls文件中讀取內容),我不想顯式加載所有的導航屬性。這是太多的代碼。所以我嘗試了一種通用的方式:

private void loadExistingNavigationProperties<TEntity>(TEntity entityToInsert) where TEntity : class 
{ 
    Type type = typeof(TEntity); 
    var properties = type.GetProperties().Except(type.GetProperties().Where(x => x.Name.Contains("id"))); 
    foreach (PropertyInfo property in properties) 
    { 
     if (property.PropertyType.FullName.Contains("MyNamespace")) 
     { 
      property.SetValue(entityToInsert, findNavigationProperty<???>(property.GetValue(entityToInsert))); 
     } 
    } 
} 

我有我的entityToInsert。如果它有一個導航屬性(contains("MyNamespace")),我檢查它的所有屬性。如果這是真的,導航屬性應該加載(見下文)並設置。

private object findNavigationProperty<TNavigationProperty>(TNavigationProperty navigationPropertyValue) where TNavigationProperty : class 
{ 
    List<TNavigationProperty> navigationProperties = GetAllEntries<TNavigationProperty>(); 
    foreach (var entity in navigationProperties) 
    { 
     if (propertiesAreEqual(entity, navigationPropertyValue)) 
     { 
      return entity; 
     } 
    } 
    return navigationPropertyValue; 
} 

導航屬性屬性的當前值被傳遞。它包含所有信息,如名稱或其他內容,但不包含id。首先,我將獲取具有該類型的所有可用導航屬性。然後我搜索是否有一個屬性與當前屬性相同。然後這個返回並設置爲導航屬性。

編輯:

public List<TEntity> GetAllEntries<TEntity>() where TEntity : class 
{ 
    using (var dbContext = new InventarDBEntities(MainWindow.connectionName)) 
    { 
     return GetAllEntries<TEntity>(dbContext); 
    } 
} 

public List<TEntity> GetAllEntries<TEntity>(InventarDBEntities dbContext) where TEntity : class 
{ 
    return dbContext.Set<TEntity>().ToList(); 
} 

問題

我的問題是,現在我該怎麼告訴方法findNavigationProperty的通用類型爲類型,該屬性的值了。因此用類型替換???

+1

您無法在運行時檢索泛型類型。泛型類型必須在編譯期間可解析。如果您想將運行時解析類型傳遞給方法,則必須通過傳遞反射的System.Type來實現。 GetAllEntries()是否有一個接受「System.Type」參數的重載? –

+0

@NoelWidmer我添加了GetAllEntries方法。它不接受System.Type的參數 – L3n95

+0

你是否也有'InventarDBEntities'的來源?我想它是一個.NET類型。在這種情況下,你能告訴我它所源自的類名的名字嗎? (我想看看是否有一個'InventarDBEntities.Set()'重載,它接受'System.Type'而不是泛型參數) –

回答

1

由於我在我的評論中已經提到:
泛型類型參數在編譯期間被解析。
因此,您無法從System.Type檢索通用類型。

您的問題的關鍵是使用System.Type而不是泛型。
請注意,我沒有測試下面的代碼,因爲我沒有安裝EF。
我的kowledge DbContext的System.Type重載應該工作得很好。

private void loadExistingNavigationProperties<TEntity>(TEntity entityToInsert) where TEntity : class 
{ 
    Type tEntity = typeof(TEntity); 
    var properties = tEntity.GetProperties().Except(tEntity.GetProperties().Where(x => x.Name.Contains("id"))); 
    foreach (PropertyInfo property in properties) 
    { 
     if (property.PropertyType.FullName.Contains("MyNamespace")) 
     { 
      object val = findNavigationProperty(property.GetValue(entityToInsert), tEntity); 
      property.SetValue(entityToInsert, val); 
     } 
    } 
} 

private object findNavigationProperty(object navigationPropertyValue, Type tEntity) 
{ 
    DbSet navigationProperties = GetAllEntries(tEntity); 
    foreach (var entity in navigationProperties) 
    { 
     // You may get a type issue. 
     // If so: cast to the correct type or change "propertiesAreEqual". 
     if (propertiesAreEqual(entity, navigationPropertyValue)) 
     { 
      return entity; 
     } 
    } 
    return navigationPropertyValue; 
} 

public DbSet GetAllEntries(Type tEntity) 
{ 
    using (var dbContext = new InventarDBEntities(MainWindow.connectionName)) 
    { 
     return GetAllEntries(dbContext, tEntity); 
    } 
} 

public DbSet GetAllEntries(InventarDBEntities dbContext, Type tEntity) 
{ 
    return dbContext.Set(tEntity); 
} 
+0

是的,它的工作原理。而且它比通過反射調用方法要乾淨得多。謝謝。我只是不明白爲什麼DbSet比DbSet <>有更少的方法,但這是另一個問題,演員也解決了這個問題。 – L3n95

+0

@ L3n95酷!我沒有經常使用DbSet,因此不能回答這個問題。我總是比普通對象類型更喜歡泛型類型。但是在使用反射類型的情況下,你通常沒有更好的選擇。 –

0

您可以檢索一個泛型類型如下:

var item = propertyInfo.GetGenericArguments()[0]; 

您可以檢查它是否是一個類型的用「是」

你也可以這樣做:

item.BaseType == typeof(Whatever type your navigation props inherit);