【问题标题】:Iterating all Entity Framework DbSets that implement an Interface using reflection使用反射迭代所有实现接口的实体框架 DbSet
【发布时间】:2015-06-17 16:04:58
【问题描述】:

我的一些实体框架类实现了某个接口,比如IHasYearColumn,这意味着该表有一个year 列(int)。

我想遍历所有带有年份列的表并做一些工作。

我设法使用以下方法获取相关类型:

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

我验证了这是可行的,并且确实得到了我想要的所有类型。

现在,我想遍历各个表,从所有记录中获取年份值:

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

这显然不会编译,因为t 未被识别为IHasYearColumn。因此,我尝试将 typesWithYear 中的所有类型转换为 IHasYearColumn 但这无济于事。我收到了InvalidCastException

欢迎任何想法。

编辑 找到答案here

【问题讨论】:

    标签: c# entity-framework reflection types interface


    【解决方案1】:

    这是一个对我有用的解决方案。 IHaveSpecificIdNo 是我对最初问题 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
                    }
                }
    

    【讨论】:

      【解决方案2】:

      这可能有效:

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

      【讨论】:

      • InvalidCastException: Cannot create DbSet&lt;IHasYearColumn&gt; from a non-generic DbSet for objects of type ...
      • 添加了AsQueryable()。不提供DbSet,但您有一份工作清单。我没有一个活跃的项目来测试这些但再试一次,为什么不:-)
      • LINQ to Entities only supports casting EDM primitive or enumeration types.
      【解决方案3】:

      首先,你获取类型的代码包括接口本身,所以你需要添加额外的谓词:

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

      接下来,使用非泛型方法获取 dbSet:

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

      此外,我不确定 EF 是否会管理强制转换为接口以生成 SQL。如果没有(您可以像 GDS 建议的那样尝试),您可以使用 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 确实支持转换为实体模型或原始类型。

      【讨论】:

        猜你喜欢
        • 2013-04-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多