调用泛型方法时使用 PropertyInfo 作为泛型类型

Use PropertyInfo as generic type when calling a generic method

背景

我正在使用 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 通用类型是 属性 的值所具有的类型。所以用 type.

替换 ???

您可以像这样检索通用类型:

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

可以使用"is"

检查是否是类型

您还可以这样做:

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

正如我在评论中提到的那样:
泛型类型参数在编译时解析。
因此,您无法从 System.Type 检索通用类型。

您的问题的关键是使用 System.Type 而不是泛型。
请注意,我没有测试下面的代码,因为我还没有安装 EF。
根据我的知识,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);
}