【问题标题】:EF Code First recursive Query with IEnumerable<>?使用 IEnumerable<> 的 EF 代码优先递归查询?
【发布时间】:2012-07-17 23:50:58
【问题描述】:

我有一个“菜单”表,其中有一个 ParentId 列。我的 LINQ 查询就在下面。

    public IEnumerable<MenuTableObject> GetMenus ( int? parentId ) {
        var result = ( from m in _db.Menus
                       join ml in _db.MenuLanguages on m.Id equals ml.MenuId
                       join l in _db.Languages on ml.LanguageId equals l.Id
                       where l.Code == Thread.CurrentThread.CurrentCulture.Name
                             && m.ParentId == ( parentId.HasValue ? parentId : null )
                       select new MenuTableObject {
                           Action = m.Action,
                           Controller = m.Controller,
                           Id = m.Id,
                           Title = ml.Title,
                           SubMenus = this.GetMenus( m.Id )
                       } );

        return result;
    }

这里是 MenuTableObject 类。

public class MenuTableObject {
    public int Id { get; set; }
    public string Title { get; set; }
    public string Controller { get; set; }
    public string Action { get; set; }
    public IEnumerable<MenuTableObject> SubMenus { get; set; }
}

这是我在下面得到的例外。

LINQ to Entities does not recognize the method 'System.Collections.Generic.IEnumerable`1[IstanbulHairCenter.Data.Service.MenuTableObject] GetMenus(System.Nullable`1[System.Int32])' method, and this method cannot be translated into a store expression.

我该怎么做才能克服这个问题?

【问题讨论】:

    标签: c# entity-framework ef-code-first


    【解决方案1】:

    根据经验,您不能在任何 EF IQueryable 查询中使用自定义函数(可能存在扩展点,但不确定)。

    每个IQueryable 查询都是expression tree,而不是函数(注意IQueryable Where() 采用Expression&lt;Func&lt;T, bool&gt;&gt; 而不是Func&lt;T, bool&gt;)。树是由具体实现(本例中为实体框架)分析并映射成一个SQL字符串。

    每个映射都必须由实现者显式创建。 EF 告诉您它不知道如何处理您的 GetMenus() 方法(即来自 GetMenus() 的映射 -> SQL 不存在)。

    解决方法是从数据库中提取所有相关数据,然后使用 LINQ to Object 而不是 LINQ to Entities 运行查询。

    递归不是真正的原因。在调用第一个递归 GetMenus() 之前的某个时间,您需要在您的实体上使用 ToList()(或 AsEnumerable() - 虽然不确定)。或者您可以编写一个 StoredProc 或其他东西,然后将其从上下文或 DbSet 中调用。

    【讨论】:

    • @lain: 可以对IQueryable 进行一些有限的扩展。有一个(非官方的)微软项目允许这样做。不过我不记得它的名字了。
    【解决方案2】:

    您必须遍历 LINQ 查询之外的结果以填充 SubMenus,因为 EF 无法将 GetMenus 方法转换为 SQL。

    public IEnumerable<MenuTableObject> GetMenus ( int? parentId ) {
        var result = ( from m in _db.Menus
                       join ml in _db.MenuLanguages on m.Id equals ml.MenuId
                       join l in _db.Languages on ml.LanguageId equals l.Id
                       where l.Code == Thread.CurrentThread.CurrentCulture.Name
                             && m.ParentId == ( parentId.HasValue ? parentId : null )
                       select new MenuTableObject {
                           Action = m.Action,
                           Controller = m.Controller,
                           Id = m.Id,
                           Title = ml.Title
                       } ).ToList();
    
        foreach(var menu in result)
        {
            menu.SubMenus = this.GetMenus(menu.Id);
        }
    
        return result;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-26
      • 2012-05-17
      相关资源
      最近更新 更多