我有2个相关的Linq to SQL问题。请看下面的图片,看看我的模型是什么样的。
问题1
我正在尝试计算如何在我的User.AddedByUser
类/表上加载User
字段。此字段是根据User.AddedByUserId
字段上的关系生成的。该表是自引用的,我试图找出如何让Linq to SQL急切地加载User.AddedByUser
属性,即每当加载/获取任何User
实体时,它也必须获取User.AddedByUser和User.ChangedByUser。但是,据我所知,这可能会成为一个递归问题...
更新1.1:
我尝试使用DataLoadOptions,如下所示:
var options = new DataLoadOptions();
options.LoadWith<User>(u => u.ChangedByUser);
options.LoadWith<User>(u => u.AddedByUser);
db = new ModelDataContext(connectionString);
db.LoadOptions = options;
但这不起作用,我在第2行得到以下异常:
System.InvalidOperationException occurred
Message="Cycles not allowed in LoadOptions LoadWith type graph."
Source="System.Data.Linq"
StackTrace:
at System.Data.Linq.DataLoadOptions.ValidateTypeGraphAcyclic()
at System.Data.Linq.DataLoadOptions.Preload(MemberInfo association)
at System.Data.Linq.DataLoadOptions.LoadWith[T](Expression`1 expression)
at i3t.KpCosting.Service.Library.Repositories.UserRepository..ctor(String connectionString) in C:\Development\KP Costing\Trunk\Code\i3t.KpCosting.Service.Library\Repositories\UserRepository.cs:line 15
InnerException:
异常是不言自明的 - 对象图不允许是循环的。 另外,假设第2行没有抛出异常,我很确定第3行会,因为它们是重复键。
更新1.2 :
以下内容也不起作用(不与上面的 Update 1.1 结合使用):
var query = from u in db.Users
select new User()
{
Id = u.Id,
// other fields removed for brevityy
AddedByUser = u.AddedByUser,
ChangedByUser = u.ChangedByUser,
};
return query.ToList();
它引发了以下不言自明的例外:
System.NotSupportedException occurred
Message="Explicit construction of entity type 'i3t.KpCosting.Shared.Model.User' in query is not allowed."
我现在真的不知道如何解决这个问题。请帮忙!
问题2
在我的数据库中的每个其他表上,因此在Linq to SQL模型中,我有两个字段Entity.ChangedByUser
(链接到Entity.ChangedByUserId
外键/关系)和Entity.AddedByUser
(链接到Entity.AddedByUserId
外键/关系)
如何让Linq to SQL为我加载这些字段?我是否需要对查询进行简单的连接?或者还有其他方法吗?
答案 0 :(得分:4)
Any type of cycles just aren't allowed。由于LoadWith<T>
或AssociateWith<T>
适用于上下文中的每个类型,因此没有内部方法来阻止无限循环。更准确地说,它只是混淆了如何创建SQL,因为SQL Server没有CONNECT BY
和CTEs真正超过了Linq可以使用提供的框架自动生成的内容。
您可以使用的最佳选项是为两个子项手动执行1级联接到用户表,并使用匿名类型返回它们。对不起,这不是一个干净/简单的解决方案,但到目前为止Linq确实提供了所有这些解决方案。
答案 1 :(得分:3)
也许你可以试着退后一步,看看你想要做什么与关系?我假设你想在例如用户中向用户显示这些信息。 “8小时前由Iain Galloway修改过。”
可能会有以下工作吗? : -
var users = from u in db.Users
select new
{
/* other stuff... */
AddedTimestamp = u.AddedTimestamp,
AddedDescription = u.AddedByUser.FullName,
ChangedTimestamp = u.ChangedTimestamp,
ChangedDescription = u.ChangedByUser.FullName
};
我在那里使用匿名类型(imo)清晰度。如果您愿意,可以将这些属性添加到用户类型中。
至于你的第二个问题,你的普通LoadWith(x =&gt; x.AddedByUser)等应该可以正常工作 - 尽管我倾向于直接在数据库中存储描述字符串 - 你需要权衡在ChangedByUser.FullName更改时你的描述更新和必须做一些复杂的事情之间,如果ChangedByUser被删除可能违反直觉(例如ON DELETE CASCADE,或在你的代码中处理null ChangedByUser)。
答案 2 :(得分:0)
不确定Linq to Sql是否存在此问题的解决方案。如果您使用的是Sql Server 2005,则可以定义一个(递归的)Stored Procecdure,它使用公共表表达式来获取您想要的结果,然后使用DataContext.ExecuteQuery执行该结果。