我有一个“菜单”表,其中有一个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.
我该怎么做才能克服这个问题?
答案 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;
}