如何查询实现接口的所有表

时间:2014-10-15 14:41:11

标签: c# asp.net-mvc linq entity-framework

我已经为我的一些实体类实现了一个接口:

public partial class Order : IReportable
{
   public string TableName { get { return "Order"; } }
}

public partial class Client: IReportable
{
 public string TableName { get { return "Client"; } }
}


public interface IReportable
{
    string TableName { get; }
}

然后我将其添加到DbContext:

public virtual DbSet<IReportable> IReportable { get; set; }

当我尝试查询实现此接口的所有表时(如此处所示):

var result = from reportabletable in db.IReportable
             where reportabletable.TableName == table_name
            select reportabletable

我得到以下异常:

  

类型&#39; Report.DataAccess.IReportable&#39;没有映射。检查一下   尚未使用Ignore方法明确排除该类型   或NotMappedAttribute数据注释。验证类型是否   定义为类,不是原始的或通用的,并且不继承   来自EntityObject。

4 个答案:

答案 0 :(得分:6)

我会选择这样的事情:

创建此扩展方法

public static class DbContextExtensions
{
    public static IEnumerable<T> SetOf<T>(this DbContext dbContext) where T : class
    {
        return dbContext.GetType().Assembly.GetTypes()
            .Where(type => typeof(T).IsAssignableFrom(type) && !type.IsInterface)
            .SelectMany(t => Enumerable.Cast<T>(dbContext.Set(t)));
    }
}

并像这样使用它:

using (var db = new dbEntities())
{
 var result = from reportabletable in db.SetOf<IReportable>()
         where reportabletable.TableName == table_name
        select reportabletable
}

答案 1 :(得分:2)

EF并不喜欢将接口直接映射到表。您可以通过使用通用存储库来解决这个问题,如Here!

所述

然后使用存储库方法并提供要查询的表的类型。类似于:myRepo.GetAll<myClient.GetType()>();

获取继承该接口的类并运行所有这些接口的查询:

var types = System.Reflection.Assembly.GetExecutingAssembly().GetTypes().Where(mytype => mytype .GetInterfaces().Contains(typeof(myInterface)));
foreach (var mytype in types)
 { // aggregate query results }

希望这有帮助!可能有更优雅的解决方案

答案 2 :(得分:1)

首先,MarcGravell评论的是钱。由您决定要查询哪个表。 我个人查看实现接口或具有自定义属性的poco类型列表。但是,如果您只想通过DBContext,那么这里有一些扩展可以让您访问“名称”。您仍然需要一次一个地访问该部分上下文。

你可以通过泛型来做到这一点,但你可以直接按照你的建议去做 您需要迭代一个类型列表。 例如:

  

ReportRespository:BaseRespository,其中t:IReport

检查程序集中的某些类型和属性 例如

     /// <summary>
    /// POCOs that have XYZ Attribute of Type  and NOT abstract and not complex
    /// </summary>
    /// <returns></returns>
    public static List<Type> GetBosDirDBPocoList() {
        var result = new List<Type>();
        // so get all the Class from teh assembly that public non abstract and not complex
        foreach (var t in Assembly.GetExecutingAssembly().GetTypes()
                                  .Where(t => t.BaseType != null
                                              && t.IsClass
                                              && t.IsPublic
                                              && !t.IsAbstract
                                              && !t.IsComplexType()
                                              && t.GetMyAttribute() != null)) {


                result.Add(t);
            }
        }
        return result;
    }

     public static GetMyAttribute(this Type T) {
        var myAttr= T.GetCustomAttributes(true)
                      .Where(attribute => attribute.GetType()
                      .Name == "XYZAttr").Cast<BosDir>().FirstOrDefault();

        return myAttr;
    }

<强>扩展

 public static class DalExtensions {
    // DbSet Names is the plural property name in the context
    public static List<string> GetModelNames(this DbContext context) {
        var propList = context.GetType().GetProperties();
        return GetDbSetNames(propList);
    }

    // DbSet Names is the plural property name in the context
    public static List<string> GetDbSetTypeNames<T>() where T : DbContext {
        var propList = typeof (T).GetProperties();
        return GetDbSetNames(propList);
    }

    // DBSet Types is the Generic Types POCO name  used for a DBSet
    public static List<string> GetModelTypes(this DbContext context) {
        var propList = context.GetType().GetProperties();
        return GetDbSetTypes(propList);
    }

    // DBSet Types POCO types as IEnumerable List
    public static IEnumerable<Type> GetDbSetPropertyList<T>() where T : DbContext {
        return typeof (T).GetProperties().Where(p => p.PropertyType.GetTypeInfo()
                                                      .Name.StartsWith("DbSet"))
                         .Select(propertyInfo => propertyInfo.PropertyType.GetGenericArguments()[0]).ToList();
    }

    // DBSet Types is the Generic Types POCO name  used for a DBSet
    public static List<string> GetDbSetTypes<T>() where T : DbContext {
        var propList = typeof (T).GetProperties();
        return GetDbSetTypes(propList);
    }


    private static List<string> GetDbSetTypes(IEnumerable<PropertyInfo> propList) {
        var modelTypeNames = propList.Where(p => p.PropertyType.GetTypeInfo().Name.StartsWith("DbSet"))
                                     .Select(p => p.PropertyType.GenericTypeArguments[0].Name)
                                     .ToList();
        return modelTypeNames;
    }

    private static List<string> GetDbSetNames(IEnumerable<PropertyInfo> propList) {
        var modelNames = propList.Where(p => p.PropertyType.GetTypeInfo().Name.StartsWith("DbSet"))
                                 .Select(p => p.Name)
                                 .ToList();

        return modelNames;
    }
}

}

答案 3 :(得分:0)

接受的解决方案在EF Core中不起作用。 这是我的第一个工作草案

public IEnumerable<T> SetOf<T>() where T : class
{
    var firstType = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes())
        .FirstOrDefault(type => typeof(T).IsAssignableFrom(type) && !type.IsInterface);
    if (firstType == null) return new List<T>();

    var dbSetMethodInfo = typeof(DbContext).GetMethod("Set");
    var dbSet = dbSetMethodInfo.MakeGenericMethod(firstType);

    IQueryable<T> queryable = ((IQueryable)dbSet.Invoke(this, null)).Cast<T>();

    return queryable.ToList().Cast<T>();
}

那么您可以像这样使用

_dbContext.SetOf<ISomeInterface>();

更多信息,请点击Expose method DbContext.Set(Type entityType)