1

私は現在、Nhibernate 3.2 で SqlServer データベースにヒットする c# を使用しており、マルチクエリと Futures を使用して子コレクションをロードしようとしています。

とにかく、Linq to Nhibernate を使用して動作させることができますが、SQL がデータベースに送信されるのを見ると、子コレクション fetch の子オブジェクトに加えて、すべての親オブジェクトをロードしているように見えます (熱心なように読み込み中)。必要な子オブジェクト列のみをプルするようにこの動作を変更できるかどうかに興味がありました。

この問題を説明するコードの例を次に示します。

  public class Parent : Entity
   {
      public virtual string Name { get; set; }
      public virtual IList<Child> Children { get; set; }
   }


public class Child : Entity
   {
      public virtual int Age { get; set; }
      public virtual string Name { get; set; }
      public virtual Parent Parent { get; set; }
   }


public class ChildClassMap : ClassMap<Child>
   {
      public ChildClassMap()
      {
         Id(x => x.Id,"Id");
         Map(x => x.Age);
         Map(x => x.Name);
         this.References(x => x.Parent).Column("ParentId").ForeignKey("Id");
      }
   }


 public class ParentClassMap : ClassMap<Parent>
   {
      public ParentClassMap()
      {
         Id(x => x.Id, "Id");
         Map(x => x.Name);
         this.HasMany(x => x.Children).KeyColumn("ParentId");
      }
   }



  public class FamilyRepository : NHibernateRepository<Parent>
   {
      public Parent GetParent(int id)
      {
         using (var session = this.Session.OpenSession())
         {
            var parent = session.Query<Parent>()
               .Where(p => p.Id == id);

            parent.FetchMany(x => x.Children)
               .ToFuture();

            return parent.ToFuture().SingleOrDefault();
         }
      }
   }

テストケース

   [TestClass]
   public class FamilyTests
   {
      [TestMethod]
      public void Should_Get_Parent_And_Children()
      {
         // arrange
         var repo = new FamilyRepository();

         // act
         var parent = repo.GetParent(1);

         // assert
         Assert.AreNotEqual(null, parent);
         Assert.AreEqual("TheOldOne", parent.Name);
         Assert.AreEqual(3, parent.Children.Count);
         Assert.AreEqual(4, parent.Children[1].Age);
         Assert.AreEqual("TheMiddleOne", parent.Children[1].Name);

      }
   }

SQL:

CREATE TABLE [dbo].[Parent](
   [Id] [int] IDENTITY(1,1) NOT NULL,
   [Name] [varchar](50) NOT NULL,
CONSTRAINT [PK_Parent] 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]
GO

CREATE TABLE [dbo].[Child](
   [Id] [int] IDENTITY(1,1) NOT NULL,
   [ParentId] [int] NOT NULL,
   [Age] [int] NOT NULL,
   [Name] [varchar](50) NOT NULL,
CONSTRAINT [PK_Child] 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]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[Child]  WITH CHECK ADD  CONSTRAINT [FK_Child_Parent] FOREIGN KEY([ParentId])
REFERENCES [dbo].[Parent] ([Id])
GO

ALTER TABLE [dbo].[Child] CHECK CONSTRAINT [FK_Child_Parent]
GO


Set Identity_Insert [dbo].[Parent] on 
insert into [dbo].[Parent]
(Id, Name)
values (1, 'TheOldOne');

insert into [dbo].[Parent]
(Id, Name)
values (2, 'TheOtherOne');
Set Identity_Insert [dbo].[Parent] off
GO

Set Identity_Insert [dbo].[Child] on
insert into [dbo].[Child]
(Id, ParentId, Age, Name)
values(1,1,3,'TheYoungOne')


insert into [dbo].[Child]
(Id, ParentId, Age, Name)
values(2,1,4,'TheMiddleOne')


insert into [dbo].[Child]
(Id, ParentId, Age, Name)
values(3,1,7,'TheFirstOne')
Set Identity_Insert [dbo].[Child] off

SQL プロファイラーからの出力は次のとおりです。

exec sp_executesql N'
    select parent0_.Id as Id3_0_, children1_.Id as Id2_1_, parent0_.Name as Name3_0_, children1_.Age as Age2_1_, children1_.Name as Name2_1_, children1_.ParentId as ParentId2_1_, children1_.ParentId as ParentId0__, children1_.Id as Id0__ 
    from [Parent] parent0_ left outer join [Child] children1_ on parent0_.Id=children1_.ParentId where parent0_.Id=@p0;
    select parent0_.Id as Id3_, parent0_.Name as Name3_ from [Parent] parent0_ where parent0_.Id=@p1;
',N'@p0 bigint,@p1 bigint',@p0=1,@p1=1

誰か提案はありますか?

御時間ありがとうございます

4

1 に答える 1

1

コードを短くするだけです

public Parent GetParentWithChildrenInitialised(int id)
{
    using (var session = SessionFactory.OpenSession())
    {
        return session.Query<Parent>()
           .Where(p => p.Id == id)
           .FetchMany(x => x.Children)
           .SingleOrDefault();
    }
}

個人的には、不要な抽象化が追加され、パフォーマンスの調整が難しくなるため、リポジトリを削除します。ISession は既にリポジトリのようなものです。

session.Get(parentId);子が必要な場合は、lvl1/session キャッシュまたは上記のクエリを使用するため、代わりに使用することをお勧めします。

また、sessionfactory を使用してセッションを作成します。これはスレッドセーフですが、セッションはそうではありません。

于 2012-11-14T19:27:18.977 に答える