How to query all tables that implement an interface

I have applied an interface for some of my entity classes:

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; }
}

      

Then I added this to the DbContext:

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

      

When I try to query all tables that implement this interface (as shown here):

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

      

I am getting the following exception:

The type "Report.DataAccess.IReportable" was not displayed. Check that the type has not been explicitly excluded using the Ignore or NotMappedAttribute method of the data annotation. Make sure the type you define as a class is not primitive or generic and does not inherit from EntityObject.

+4


source to share


4 answers


I would go for something like this:

Create this extension method

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)));
    }
}

      



And use it like this:

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

      

+6


source


EF doesn't like mapping interfaces directly to tables. You can get around this by using a shared repository as described here!

Then use the repository method and specify the type of table (s) you want to query. Something like:myRepo.GetAll<myClient.GetType()>();

Get classes that inherit this interface and query for all of them:



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

      

Hope this helps! Perhaps a more graceful solution

+2


source


First of all, MarcGravell's comment on Money. It's up to you to know which table to query. Personally, I go through a list of poco types that implement an interface or have a custom attribute. But if you only want to navigate through DBC text, here are some extensions that give you access to "names". You will still need to access this portion of the context one at a time.

Again, you can do this with generics, but you can just go straight ahead as you suggest.
You will need to iterate over the list of types. eg:

ReportRespository: BaseRespository, where t: IReport

Check assembly for specific types and attributes eg

     /// <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;
    }

      

Extensions

 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;
    }
}

      

}

+1


source


The accepted solution does not work in EF Core. Here is my first working draft

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>();
}

      

Then you could use like this

_dbContext.SetOf<ISomeInterface>();

      

More details here Expose method DbContext.Set (Type entityType)

0


source







All Articles