1

Some of my Entity Framework classes implement a certain interface, say IHasYearColumn, which means the table has a year column (int).

I would like to iterate over all of the tables with year columns and do some work.

I managed to get the relevant types using:

 var typesWithYear = AppDomain.CurrentDomain.GetAssemblies()
 .SelectMany(a=>a.GetTypes())
 .Where(t=>typeof(IHasYearColumn).IsAssignableFrom(t);

I verified this works, and indeed I get all the types I want.

Now, I would like to iterate over the respective table get the year values from all the records:

foreach (t in typesWithYear)
   myDbEntites.Set<t>().Select(x=>x.Year);

This obviously won't compile since t is not recognized as IHasYearColumn. So, I tried casting all types in typesWithYear into IHasYearColumn but this would not help. I got an InvalidCastException.

Any ideas will be most welcomed.

Edit Found the answer here.

Community
  • 1
  • 1
Brook Must
  • 33
  • 5

3 Answers3

1

Here is a solution that worked for me. IHaveSpecificIdNo is my analog to the initial questions IHasYearColumn

    var currentSpecificId = "123";

var DataContext = this;
var setProps = DataContext
            .GetType()
            .GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(x => 
            {
                return x.PropertyType.IsGenericType 
                //todo better check
                &&  x.PropertyType.Name.StartsWith("DbSet");
            })
            .ToArray();


            foreach (var setProperty in setProps)
            {
                var entityType = setProperty.PropertyType.GetGenericArguments().First();
                var set = DataContext.Set(entityType);

                if (typeof (IHaveSpecificIdNo).IsAssignableFrom(entityType))
                {
                    var items = ((IQueryable<IHaveSpecificIdNo>)set)
                                    .Where(x => x.SpecificIdNo == currentSpecificId).ToArray();
                    if(items.Length == 0)
                    {
                        continue;
                    }
                    //do something
                }
            }
Ivan Koshelev
  • 3,830
  • 2
  • 30
  • 50
0

This might work:

foreach (t in typesWithYear)    
  myDbEntites.Set(t).AsQueryable().Cast<IHasYearColumn>().Select(x=>x.Year);
GDS
  • 1,337
  • 12
  • 18
  • `InvalidCastException: Cannot create DbSet from a non-generic DbSet for objects of type ...` – Brook Must Apr 12 '15 at 08:36
  • Added `AsQueryable()`. Doesn't give a `DbSet` but you have a list to work on. I don't have an active project to test these but give it another try, why not :-) – GDS Apr 12 '15 at 09:21
  • `LINQ to Entities only supports casting EDM primitive or enumeration types`. – Brook Must Apr 12 '15 at 11:04
0

First of all, your code for getting types include interface itself, so you need to add additional predicate:

 var typesWithYear = AppDomain.CurrentDomain
                              .GetAssemblies()
                              .SelectMany(a=>a.GetTypes())
                              .Where(t=>typeof(IHasYearColumn)
                                          .IsAssignableFrom(t))
                              .Where(t => t.IsClass && !t.IsAbstract);

Next, use non-generic method for getting dbSet:

foreach (var type in typesWithYear)
{
    var set = myDbEntites.Set(type);

}

What's more, I'm not sure that EF will manage cast to an interface in order to produce SQL. If no (you can try it like GDS proposed), you can use Dynamic LINQ:

foreach (var type in typesWithYear)
{
    var set = myDbEntites.Set(type);
    yield return ((IQueryable)set).Select("Year")
                                  .Cast<int>(); // or sth else, your choice
}

EF supports casting to entity models or primitive type for sure.