使用IEnumerable<&gt ;?的EF Code First递归查询

时间:2012-07-17 23:50:58

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

我有一个“菜单”表,其中有一个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.

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

2 个答案:

答案 0 :(得分:0)

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

每个IQueryable查询都是expression tree,而非func(请注意IQueryable Where()采用Expression<Func<T, bool>>而不是Func<T, bool>) 。树由特定实现(在本例中为Entity框架)进行分析,并映射到SQL字符串。

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

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

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

中调出

答案 1 :(得分:0)

您必须遍历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;
}