7

我有 2 个相关的 Linq to SQL 问题。请看下图,看看我的模型是什么样子的。

问题 1

我想弄清楚如何在我的 类/表上急切地加载该User.AddedByUser字段。User该字段是根据User.AddedByUserId字段上的关系生成的。该表是自引用的,我试图弄清楚如何让 Linq to SQLUser.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

以下内容也不起作用(不与上面的更新 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 急切地为我加载这些字段?我需要对我的查询进行简单的连接吗?还是有其他方法?

Linq to SQL 急切加载自引用表 http://img245.imageshack.us/img245/5631/linqtosql.jpg

4

3 回答 3

4

任何类型的循环都是不允许的。由于LoadWith<T>orAssociateWith<T>应用于上下文中的每种类型,因此没有内部方法可以防止无限循环。更准确地说,它只是对如何创建 SQL 感到困惑,因为 SQL Server 没有,CONNECT BY而且CTE确实超过了 Linq 可以使用提供的框架自动生成的东西。

您可以使用的最佳选择是手动执行 1 级连接到用户表的两个孩子和匿名类型以返回它们。抱歉,这不是一个干净/简单的解决方案,但它确实是迄今为止 Linq 可用的全部。

于 2009-09-09T01:19:11.597 回答
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 => x.AddedByUser) 等应该可以正常工作-尽管我倾向于将描述字符串直接存储在数据库中-您需要在描述更新之间进行权衡当 ChangedByUser.FullName 发生变化时,如果 ChangedByUser 被删除(例如 ON DELETE CASCADE,或在代码中处理 null ChangedByUser),则必须做一些复杂且可能违反直觉的事情。

于 2009-09-08T13:06:23.023 回答
0

不确定 Linq to Sql 是否有解决此问题的方法。如果您使用的是 Sql Server 2005,您可以定义一个(类似递归的)存储过程,它使用公用表表达式来获取您想要的结果,然后使用 DataContext.ExecuteQuery 执行该结果。

于 2009-09-08T04:09:02.887 回答