我正在努力想出正确的词来概括这个问题,所以我可以赞赏任何关于我可以添加以澄清它的信息。
基本情况是这样的:我有一个基本的CMS(包括页面,用户等)。 Page是一个LINQ数据对象,它直接映射到Page表。
我在Page类中添加了一个名为GetUserPermissions的方法。此方法接受UserId并返回一个名为PagePermissionSet的非LINQ类,该类描述了用户可以执行的操作。 PagePermissionSet是通过LINQ查询计算的。
现在我想获取用户有权访问的Pages列表。理想的实施方式如下:
from page in mDataContext.Pages
where page.GetUserPermissions(userId).CanView
select page
这失败了,说明GetUserPermissions没有SQL等价物(这是合理的),或者在重构方法之后,无法在IQueryable上调用CanView成员。
尝试两种方法是向DataContext添加一个方法,该方法将每个页面/用户的所有权限作为IQueryable返回:
IQueryable<PagePermissionSet> GetAllPagePermissions()
然后我尝试加入这个结果集:
IQueryable<Page> GetAllPages(Guid? userId) {
var permissions = mDataContext.GetAllPagePermissions();
var pages =
from page in mDataContext.WikiPages
join permission in permissions on Page.FileName equals permission.PageName
where permission.CanView && permission.UserId == userId
select page;
return pages;
}
这会产生错误:“成员'WikiTome.Library.Model.PagePermissionSet.PageName'没有支持的SQL转换。”
PagePermissionSet几乎只是一个包含GetUserPermissions中select子句数据的shell,并初始化如下:
select new PagePermissionSet(pageName, userName, canView, canEdit, canRename)
完成所有这些...如何在另一个查询中重用Page.GetUserPermissions中的LINQ查询?我绝对不想复制代码,我宁愿不将它翻译成SQL以包含在视图中。
答案 0 :(得分:1)
答案 1 :(得分:1)
您有几个选择。
1)快速而肮脏的解决方案是在查询中使用AsEnumerable()
将整个Pages
表格下移到客户端,然后对其进行操作。对于小型表,这应该没问题,但是对于大型表,它将是低效的并且导致性能问题取决于大小。如果您选择使用它,请注意它实际操作的方式。这意味着将代码更新为:
from page in mDataContext.Pages.AsEnumerable()
where page.GetUserPermissions(userId).CanView
select page
2)更复杂的解决方案是在SQL服务器上创建存储过程或UDF,您将从DataContext调用并将参数传递给它。看看Scott Gu的博文:LINQ to SQL (Part 6 - Retrieving Data Using Stored Procedures)。
然后您可以编写如下内容:
mDataContext.GetUserPermissions(userId)
您在代码中执行的所有逻辑都将使用SQL编写,您将返回给定用户的可查看页面。这会绕过使用没有受支持的SQL转换的PagePermissionSet
属性。
答案 2 :(得分:0)
我今天能够解决大部分问题。
错误“成员'WikiTome.Library.Model.PagePermissionSet.PageName'没有支持的SQL转换。”是由我如何初始化我的PagePermissionSet对象引起的。
我一直在使用构造函数初始化它们,如下所示:
select new PagePermissionSet(pageName, userName, canView, canEdit, canRename)
但是,为了使LINQ正确跟踪属性,需要将其初始化为:
select new PagePermissionSet { PageName=pageName, UserName = userName, CanView = canView, CanEdit = canEdit, CanRename = canRename }
有了这个改变,我可以创建一个返回IQueryable<PagePermissionSet>
的方法,然后将我的查询加入到该方法中(如第二个例子中所示)。