1

我有一个 Task 实体,它有一个前面和后面的任务:

namespace OneToOneIssue.Domain
{
    public class Task
    {
        public virtual Guid Id { get; set; }
        public virtual string Description { get; set; }
        public virtual Task FollowingTask { get; set; }
        public virtual Task PrecedingTask { get; set; }
    }
}

数据库表如下所示:

CREATE TABLE [dbo].[Task](
    [Id] uniqueidentifier NOT NULL,
    [Description] nvarchar(100) NULL,
    [FollowingTaskId] uniqueidentifier NULL
    CONSTRAINT [PK_Task] PRIMARY KEY CLUSTERED 
    (
        [Id] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

INSERT INTO [Task] ([Id], [Description], [FollowingTaskId]) VALUES ('30efbfda-f3b5-42fb-906e-098fb32be79d', 'Task 1', 'f7367187-406d-47db-931e-b9e4fa8a4774')
INSERT INTO [Task] ([Id], [Description], [FollowingTaskId]) VALUES ('f7367187-406d-47db-931e-b9e4fa8a4774', 'Task 2', '42c25da5-7c04-4adc-a9c2-6bf8a9ff5c89')
INSERT INTO [Task] ([Id], [Description], [FollowingTaskId]) VALUES ('42c25da5-7c04-4adc-a9c2-6bf8a9ff5c89', 'Task 3', NULL)
INSERT INTO [Task] ([Id], [Description], [FollowingTaskId]) VALUES ('ffe58f51-bb85-4681-af9d-d232326a30e4', 'Task 4', 'ba2ee26c-ebbb-4d7e-a596-40db9f0711c4')
INSERT INTO [Task] ([Id], [Description], [FollowingTaskId]) VALUES ('ba2ee26c-ebbb-4d7e-a596-40db9f0711c4', 'Task 5', '29189134-8be9-4d93-873e-ce5efefe1c1a')
INSERT INTO [Task] ([Id], [Description], [FollowingTaskId]) VALUES ('29189134-8be9-4d93-873e-ce5efefe1c1a', 'Task 6', NULL)
INSERT INTO [Task] ([Id], [Description], [FollowingTaskId]) VALUES ('ef069d0a-f2a8-4c9a-8bbc-99ee1e0e2991', 'Task 7', '56a6eb57-ab9f-49cb-875a-a072158b0265')
INSERT INTO [Task] ([Id], [Description], [FollowingTaskId]) VALUES ('56a6eb57-ab9f-49cb-875a-a072158b0265', 'Task 8', 'f8b7cc9b-269e-44c7-85bf-44592d70a21e')
INSERT INTO [Task] ([Id], [Description], [FollowingTaskId]) VALUES ('f8b7cc9b-269e-44c7-85bf-44592d70a21e', 'Task 9', NULL)

和这样的映射:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
               namespace="OneToOneIssue.Domain"
               assembly="OneToOneIssue.Domain">
  <class name="Task" table="`Task`">
    <id name="Id" column="Id" type="guid">
      <generator class="assigned"/>
    </id>
    <property name="Description" column="`Description`" />
    <many-to-one name="FollowingTask" class="Task" column="FollowingTaskId" />
    <one-to-one name="PrecedingTask" class="Task" property-ref="FollowingTask" />
  </class>
</hibernate-mapping>

现在,如果我运行查询以获取任务 2、5 和 8(唯一具有如下任务的任务:

var tasks = session
                .CreateCriteria<Task>()
                .Add(Restrictions.In("Description", new string[] {"Task 2", "Task 5", "Task 8"}))
                .List<Task>();

然后我得到了我期望的主要查询,还有一个针对所有前面任务的查询:

exec sp_executesql N'SELECT this_.Id as Id0_1_, this_.[Description] as Descript2_0_1_, this_.FollowingTaskId as Followin3_0_1_, task2_.Id as Id0_0_, task2_.[Description] as Descript2_0_0_, task2_.FollowingTaskId as Followin3_0_0_ FROM [Task] this_ left outer join [Task] task2_ on this_.Id=task2_.FollowingTaskId WHERE this_.[Description] in (@p0, @p1, @p2)',N'@p0 nvarchar(4000),@p1 nvarchar(4000),@p2 nvarchar(4000)',@p0=N'Task 2',@p1=N'Task 5',@p2=N'Task 8'
exec sp_executesql N'SELECT task0_.Id as Id0_1_, task0_.[Description] as Descript2_0_1_, task0_.FollowingTaskId as Followin3_0_1_, task1_.Id as Id0_0_, task1_.[Description] as Descript2_0_0_, task1_.FollowingTaskId as Followin3_0_0_ FROM [Task] task0_ left outer join [Task] task1_ on task0_.Id=task1_.FollowingTaskId WHERE task0_.FollowingTaskId=@p0',N'@p0 uniqueidentifier',@p0='FFE58F51-BB85-4681-AF9D-D232326A30E4'
exec sp_executesql N'SELECT task0_.Id as Id0_1_, task0_.[Description] as Descript2_0_1_, task0_.FollowingTaskId as Followin3_0_1_, task1_.Id as Id0_0_, task1_.[Description] as Descript2_0_0_, task1_.FollowingTaskId as Followin3_0_0_ FROM [Task] task0_ left outer join [Task] task1_ on task0_.Id=task1_.FollowingTaskId WHERE task0_.FollowingTaskId=@p0',N'@p0 uniqueidentifier',@p0='EF069D0A-F2A8-4C9A-8BBC-99EE1E0E2991'
exec sp_executesql N'SELECT task0_.Id as Id0_1_, task0_.[Description] as Descript2_0_1_, task0_.FollowingTaskId as Followin3_0_1_, task1_.Id as Id0_0_, task1_.[Description] as Descript2_0_0_, task1_.FollowingTaskId as Followin3_0_0_ FROM [Task] task0_ left outer join [Task] task1_ on task0_.Id=task1_.FollowingTaskId WHERE task0_.FollowingTaskId=@p0',N'@p0 uniqueidentifier',@p0='30EFBFDA-F3B5-42FB-906E-098FB32BE79D'

我什至不需要加载前面的任务。

急切地加载前面的任务也无济于事。

如果我将FollowingTask 和PrecedingTask 设置为lazy="proxy" 也无济于事。如果删除一对一映射确实可以解决问题,但这不是一个可能的解决方案。

如果您需要一对一映射,我在这里看到了有关解决问题的问题,答案似乎是它是一个错误,您只需要忍受它。但是,我什至不需要加载它。我从不访问它,它只是无缘无故地加载。我相信这个问题也是独一无二的,因为关系的递归性质。

有什么方法可以阻止它加载,还是有另一种方法可以完全实现相同的目标?

4

1 回答 1

1

只是一个建议,如何更改映射。表结构适合父子模式。我们只知道您想要一个孩子。

因为亲子有 NHibernate 强大的支持,你不会再遇到加载相关子的问题。所以,不要<ont-to-one像这样映射它。C#:

public class Task
{
  public virtual Task FollowingTask { get; set; }
  public virtual IList<Task> PrecedingTasks { get; set; }
}

映射hbm:

<many-to-one name="FollowingTask" class="Task" column="FollowingTaskId" />
<bag name="PrecedingTasks">
   <key column="FollowingTaskId"></key>
   <one-to-many class="Task"/>
</bag>

现在我们甚至可以IList<Task> PrecedingTasks创建 protected 和 createTask PrecedingTask属性来处理对第一个列表元素的get/set访问PrecedingTasks

于 2013-06-13T17:34:34.900 回答