2017-05-05 85 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);