NHibernate-지연 로딩
이 장에서는 지연 로딩 기능에 대해 다룰 것입니다. 기본적으로 완전히 다른 개념이며 NHibernate에는 지연로드가 없습니다. 예를 들어 고객을로드하면 모든 주문을로드하지 않습니다.
주문 컬렉션은 요청시로드됩니다.
다 대일이든 컬렉션이든 관계없이 모든 연결은 기본적으로 지연로드됩니다. Open ISession.
세션을 닫았거나 트랜잭션을 커밋 한 경우 이러한 추가 개체를 가져올 수없는 지연로드 예외가 발생할 수 있습니다.
지연로드와 실제로 필요한 데이터의 양에주의해야합니다.
전체 연결에 대해 지연로드를 끄거나 lazy equals false를 입력하거나 가져 오기 전략을 지정할 수도 있습니다.
여기 있습니다 Program.cs 파일 구현.
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
namespace NHibernateDemo {
internal class Program {
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
Guid id;
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var newCustomer = CreateCustomer();
Console.WriteLine("New Customer:");
Console.WriteLine(newCustomer);
session.Save(newCustomer);
id = newCustomer.Id;
tx.Commit();
}
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var reloaded = session.Load<Customer>(id);
Console.WriteLine("Reloaded:");
Console.WriteLine(reloaded);
Console.WriteLine("The orders were ordered by: ");
foreach (var order in reloaded.Orders) {
Console.WriteLine(order.Customer);
}
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
private static Customer CreateCustomer() {
var customer = new Customer {
FirstName = "John",
LastName = "Doe",
Points =100,
HasGoldStatus = true,
MemberSince = new DateTime(2012, 1, 1),
CreditRating = CustomerCreditRating.Good,
AverageRating = 42.42424242,
Address = CreateLocation()
};
var order1 = new Order { Ordered = DateTime.Now };
customer.AddOrder(order1);
var order2 = new Order {
Ordered = DateTime.Now.AddDays(-1),
Shipped = DateTime.Now,
ShipTo = CreateLocation()
};
customer.AddOrder(order2); return customer;
}
private static Location CreateLocation() {
return new Location {
Street = "123 Somewhere Avenue",
City = "Nowhere",
Province = "Alberta",
Country = "Canada"
};
}
private static Configuration ConfigureNHibernate() {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
cfg.DataBaseIntegration(x => {
x.ConnectionStringName = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect<();
x.IsolationLevel = IsolationLevel.RepeatableRead;
x.Timeout = 10;
x.BatchSize = 10;
});
cfg.SessionFactory().GenerateStatistics();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
return cfg;
}
}
}
이를 이해하기 위해 애플리케이션을 실행하고 NHibernate Profiler를 살펴 보겠습니다.
보시다시피 특정 고객 ID가 지정된 고객에서 선택이 있고 해당 고객의 컬렉션에 실제로 액세스 할 때 다른 주문에서 선택 테이블도 있습니다.
그래서 우리는 데이터베이스에 2 번 왕복합니다. 이제 때로는이를 최적화하고 싶을 것입니다. 이렇게하려면customer.hbm.xml 파일 가져 오기 전략을 추가하고 조인 가져 오기를 요청하십시오.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Customer">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "FirstName"/>
<property name = "LastName"/>
<property name = "AverageRating"/>
<property name = "Points"/>
<property name = "HasGoldStatus"/>
<property name = "MemberSince" type = "UtcDateTime"/>
<property name = "CreditRating" type = "CustomerCreditRatingType"/>
<component name = "Address">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<set name = "Orders" table = "`Order`" cascade = "all-delete-orphan"
fetch = "join">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</set>
</class>
</hibernate-mapping>
애플리케이션에서 코드를 변경하지 않았 음을 알 수 있듯이 방금 가져 오기 전략을 추가했습니다. customer.hbm.xml. 이 애플리케이션을 다시 실행 해 보겠습니다. 여전히 똑같은 방식으로 작동합니다. NHibernate Profiler를 살펴 보겠습니다.
이전에 프로그램은 데이터베이스에 대해 두 번의 왕복을 가졌지 만 지금은 하나만 있고 여기에서 왼쪽 외부 조인을 수행하기 때문입니다.
고객 ID를 기반으로 고객 테이블과 주문 테이블 사이에 왼쪽 외부 조인을 수행하고 있으므로 모든 정보를 한 번에로드 할 수 있습니다.
데이터베이스에 1 회 왕복을 저장했습니다.
단점은 고객 정보가 두 줄에 모두 복제된다는 점이며 이것이 SQL 왼쪽 외부 조인이 작동하는 방식입니다.
따라서 가져 오기 전략을 사용하면 더 많은 데이터를 가져와 왕복 시간을 절약 할 수 있습니다.
쿼리 수준에서도이 작업을 수행 할 수 있으므로 Program.cs 파일을 열고 더 간단한 다시로드 된 예제를보십시오.
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
//var query = from customer in session.Query<Customer>()
// select customer;
//var reloaded = query.Fetch(x => x.Orders).ToList();
var reloaded = session.Load<Customer>(id);
Console.WriteLine("Reloaded:");
Console.WriteLine(reloaded);
Console.WriteLine("The orders were ordered by: ");
foreach (var order in reloaded.Orders) {
Console.WriteLine(order.Customer);
}
tx.Commit();
}
여기에서 우리는 고객에 의해 부하를 받고 있습니다. 이제이를 쿼리로 변경하고 다음 코드와 같이 링크 쿼리를 사용합니다.
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var query = from customer in session.Query<Customer>()
where customer.Id == id select customer;
var reloaded = query.Fetch(x => x.Orders).ToList().First();
Console.WriteLine("Reloaded:");
Console.WriteLine(reloaded);
tx.Commit();
}
또한 가져 오기 전략을 customer.hbm.xml 파일.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Customer">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "FirstName"/>
<property name = "LastName"/>
<property name = "AverageRating"/>
<property name = "Points"/>
<property name = "HasGoldStatus"/>
<property name = "MemberSince" type = "UtcDateTime"/>
<property name = "CreditRating" type = "CustomerCreditRatingType"/>
<component name = "Address">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<set name = "Orders" table = "`Order`" cascade = "all-delete-orphan">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</set>
</class>
</hibernate-mapping>
이 애플리케이션을 다시 실행하면 다음과 같은 출력이 표시됩니다.
New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
CreditRating: Good
AverageRating: 42.42424242
Orders:
Order Id: 00000000-0000-0000-0000-000000000000
Order Id: 00000000-0000-0000-0000-000000000000
Reloaded:
John Doe (6ebacd17-f9ba-4ad8-9817-a5bb01112a5a)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: 16a6596b-d56e-41c7-9681-a5bb01112a60
Order Id: d41d615b-0f21-4032-81db-a5bb01112a61
Press <ENTER> to exit...
이제 NHibernate Profiler를 살펴보면이 열성적인 조인 가져 오기가 다시 발생하는 것을 볼 수 있지만 이번에는 쿼리를 기반으로합니다.