代码之家  ›  专栏  ›  技术社区  ›  Saajid Ismail

在自引用表中急切地加载Linq到SQL实体

  •  6
  • Saajid Ismail  · 技术社区  · 16 年前

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

    问题1

    我正试图弄清楚如何加载 User.AddedByUser 我的场地 User 班级/桌子。此字段是根据上的关系生成的 User.AddedByUserId 领域该表是自引用的,我正试图弄清楚如何让LINQtoSQL加载 急切地拥有财产,即任何时候 使用者 实体已加载/获取,它还必须获取User.AddedByUser和User.ChangedByUser。然而,我知道这可能会成为一个递归问题。。。

    更新1.1:

    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:
    

    这个异常是不言自明的——对象图不允许是循环的。

    更新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到SQL模型上,我有两个字段, Entity.ChangedByUser (链接到 Entity.ChangedByUserId 外键/关系)和 Entity.AddedByUser (链接到 Entity.AddedByUserId 外键/关系)

    如何让LinqtoSQL为我急切地加载这些字段?我需要对我的查询进行简单的连接吗?还是有其他方法?

    Linq to SQL eager loading on self referencing table http://img245.imageshack.us/img245/5631/linqtosql.jpg

    3 回复  |  直到 11 年前
        1
  •  4
  •   Nick Craver    16 年前

    Any type of cycles just aren't allowed . 自从 LoadWith<T> AssociateWith<T> 应用于上下文中的每种类型,没有内部方法可以防止无休止的循环。更准确地说,它只是对如何创建SQL感到困惑,因为SQL Server没有 CONNECT BY CTEs 实际上已经超过了Linq使用提供的框架自动生成的功能。

    您可以使用的最佳选项是手动将这两个子项的1级联接到用户表,并使用匿名类型返回它们。很抱歉,这不是一个干净/简单的解决方案,但它确实是迄今为止Linq所能提供的所有解决方案。

        2
  •  3
  •   Iain Galloway    16 年前

    和亲戚在一起?我假设您希望以“Iain Galloway 8小时前修改”等方式向用户显示此信息。

    你能做以下工作吗-

    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
                };
    

    为了(在我看来)清晰起见,我在那里使用了匿名类型。如果愿意,可以将这些属性添加到用户类型中。

    至于第二个问题,您的正常LoadWith(x=>x.addedbyser)等应该可以正常工作-虽然我倾向于直接将描述字符串存储在数据库中-在ChangedByUser.FullName更改时更新描述和在ChangedByUser被删除时必须执行一些复杂且可能违反直觉的操作之间,您有一个权衡(例如,在DELETE CASCADE上,或处理代码中的null ChangedByUser)。

        3
  •  0
  •   Simon Fox    16 年前

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