2014-10-15 2 views
3

Я реализован интерфейс для некоторых из моих классов сущностей:Как запросить все таблицы, которые реализуют интерфейс

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 

я получаю следующее исключение:

Тип «Report.DataAccess.IReportable» не был отображен. Убедитесь, что тип не был явно исключен с помощью метода Ignore или аннотации данных NotMappedAttribute. Убедитесь, что тип был , определенный как класс, не является примитивным или общим и не наследует от EntityObject.

+0

Меня удивило бы, если бы многие ORM предложили этот тип запроса –

+0

@MarcGravell Вы говорите, что это невозможно? – enb081

+1

Проверьте стратегию наследования для Entity Framework. Я не знаю, возможно ли иметь DbSet , но вы можете получить это с базовым абстрактным классом, возможно, с виртуальным (или абстрактным) свойством TableName. Btw. есть атрибут TableName - проверьте ссылки для стратегий наследования здесь - http://www.entityframeworktutorial.net/code-first/inheritance-strategy-in-code-first.aspx –

ответ

5

Я хотел бы пойти на что-то вроде этого:

Создать этот метод расширения

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

Мне нравится то, что вы здесь сделали, но можете ли вы действительно полагаться на интерфейс, определенный в той же сборке, что и таблицы контекста? Не лучше ли получить сборку из типа 'DbContext'? – Enigmativity

+1

Вы правы, нет причин для этого. Я обновил свой ответ с небольшой коррекцией. – natenho

+0

Просто обратите внимание, если ваши модели находятся в отдельной сборке из вашего контекста, это также не сработает. Просто нужно получить все сборки в AppDomain или что-то подобное. – GraemeMiller

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 } 

Надеется, что это помогает! Существует, вероятно, более изящное решение

+0

'Type' и generics не смешиваются хорошо; это можно сделать, но это неудобно. –

+0

Отражение может вызывать общий метод, передавая его Тип как аргумент. – Tengiz

1

Прежде всего Комментарий MarcGravell на деньги. Это зависит от вас, чтобы узнать, какую таблицу запросить. Лично я просматриваю список типов poco, которые реализуют интерфейс или имеют собственный атрибут. Но если вы хотите перейти только через DBC-текст, вот некоторые расширения, которые дают вам доступ к «именам». Вам по-прежнему необходимо будет получить доступ к этой части контекста после этого по одному.

Снова вы можете сделать это с помощью дженериков, но вы можете просто пойти прямо, как вы предлагаете.
Вам понадобится повторить список типов. например:

ReportRespository: BaseRespository где т: 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; 
    } 
} 

}

Смежные вопросы