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" に設定しても役に立ちません。1 対 1 のマッピングを削除すると問題は解決しますが、これは可能な解決策ではありません。

ここで、1 対 1 でマッピングする必要がある場合に問題を回避することについての質問を見てきました。答えは、それはバグであり、それと一緒に暮らす必要があるということです。ただし、ロードする必要さえありません。アクセスすることはありません。理由もなくロードするだけです。関係の再帰的な性質のために、この質問もユニークだと思います。

ロードを防ぐ方法はありますか、それとも同じことを達成する別の方法はありますか?

4

1 に答える 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>

これで、最初のリスト要素へのget/setアクセスを処理IList<Task> PrecedingTasksする protected および createTask PrecedingTaskプロパティを作成することもできます。PrecedingTasks

于 2013-06-13T17:34:34.900 に答える