The content of this section
- Introduced
- Lazy Loading
- Example analysis
- 1. One-to-many relationship instances
- 2. Many-to-many relationship instances
- Conclusion
Introduced
Through the analysis of the previous article, we know how to use nhibernate, such as crud operations, transactions, one-to-many, many-to-many mappings and other issues, this article we initially explore the nhibernate in the loading mechanism.
Before we talk, let's look at the data model we used, and review the second set of data models.
Customer and orders are a one-to-many relationship, and order is a many-to-many relationship with product. This article also uses this model to refer to articles in this series for specific configuration and mapping.
Deferred load (lazy Loading)
Deferred loading as I now understand should be called "load as needed (Load-on-demand)", "(delayed loading)", "just in Time to load (Just-in-time loading)" in the appropriate. Here the literal understanding of the delay seems to mean "delay, prolong, delay".
NHibernate deferred loading is supported by default from version 1.2. In fact, deferred loading is performed using the proxy mode in GoF23, and we use a picture to roughly demonstrate the lazy loading mechanism.
Example Analysis 1. One-to-many relationship instances
In a one-to-many relationship instance, we use the Customer object and the order object as an example to write two methods in the data access layer to be called at test time, respectively:
Method one in the data Access layer: Load the Customer object
Public Customer lazyload (int customerId) { return _session. Get<customer> (customerId);}
Method Two in the data Access layer: Load the Customer object and use the using-force cleanup to close the session
Public Customer lazyloadusingsession (int customerId) { using (isession _session = new SessionManager (). GetSession ()) { return _session. Get<customer> (customerId); }}
1. Default Lazy Loading
The Lazyload method in the call data access layer loads a customer object, and the default delay of NHibernate loads the order object associated with the customer. Use NHibernate to provide useful classes (Nhibernateutil) to test whether the associated Customer object collection has been initialized (that is, loaded).
[test]public void Lazyloadtest () { Customer customer = _relation. Lazyload (1); Assert.isfalse (nhibernateutil.isinitialized (customer. Orders));}
When the test succeeds, observe the statement that NHibernate generates the SQL statement as a query for the customer object. We use debug to find that the property value of the Orders object collection is: {Iesi.Collections.Generic.HashedSet ' 1[domainmodel.entities.order]}, And you can see the items in the Order object collection at the same time. As follows:
2. Delay loading and closing session
As with the first test, this test call uses the Using force resource cleanup method of the session load customer object.
[test]public void Lazyloadusingsessiontest () { Customer customer = _relation. Lazyloadusingsession (1); Assert.isfalse (nhibernateutil.isinitialized (customer. Orders));}
The test was successful, and its generated SQL statement is the same as the above test-generated SQL statement. However, using debug discovery, the property value of the Orders object collection is:nhibernate.collection.generic.persistentgenericset<domainmodel.entities.order>, If you want to look further at the item in the Order object collection, it throws a Hibernateexception exception: failed to lazily initialize a collection, no session or session was closed 。 As follows:
2. Many-to-many relationship instances
Similarly, in a many-to-many relationship instance, we use the order object and the Products object as an example, and we write two methods in the data access layer for testing:
Method 1: Load the Order object
Public DomainModel.Entities.Order lazyloadorderaggregate (int orderId) { return _session. Get<domainmodel.entities.order> (orderId);}
Method 2: Load the Customer object and use the using-force cleanup to close the session
Public DomainModel.Entities.Order lazyloadorderaggregateusingsession (int orderId) { using (isession _session = new SessionManager (). GetSession ()) { return _session. Get<domainmodel.entities.order> (orderId); }}
1. Default Lazy Loading
Call the Lazyloadorderaggregate method in the data access layer to load an order object, the default delay of NHibernate load the order associated products object collection (many-to-many relationships), and load the Customer object collection with proxy mode (Many-to-one relationship). Use NHibernate to provide useful classes (Nhibernateutil) to test whether the collection of associated products objects and the collection of customer objects have been initialized.
[test]public void Lazyloadorderaggregatetest () { Order order = _relation. Lazyloadorderaggregate (2); Assert.isfalse (nhibernateutil.isinitialized (order. Customer)); Assert.isfalse (nhibernateutil.isinitialized (order. Products));}
The test succeeds, and the nhibernate generates SQL statements as follows:
SELECT order0_. OrderId as orderid1_0_, order0_. Version as version1_0_, order0_. OrderDate as orderdate1_0_, order0_. Customer as Customer1_0_from [Order] order0_ WHERE [email protected]; @p0 = ' 2 '
debugging to see the effect, you can clearly observe the customer object and the type of products object collection.
2. Delay loading and closing session
As with the first test, this test call uses the Using force resource cleanup method of the session load order object.
[test]public void Lazyloadorderaggregateusingsessiontest () { Order order = _relation. Lazyloadorderaggregateusingsession (2); Assert.isfalse (nhibernateutil.isinitialized (order. Customer)); Assert.isfalse (nhibernateutil.isinitialized (order. Products));}
The test was successful, and its generated SQL statement is the same as the above test-generated SQL statement. However, using debug discovery, the Customer object type is: {CUSTOMERPROXY9DFB54ECA50247F69BFEDD92E1638BA5}, further observing that the Customer object FirstName, LastName, and so on, raised the " Nhibernate.lazyinitializationexception "type of exception. The property values for the Products object collection are: {nhibernate.collection.generic.persistentgenericbag<domainmodel.entities.product>}, If you want to look further at the items in the Products object collection It also throws an Hibernateexception exception: failed to lazily initialize a collection, no session or session was CLO Sed. The following intercept gets a part of the Customer object diagram, you want to know all yourself debugging a piece:
3. lazyinitializationexception Exceptions in deferred loading
The above test has explained the problem: if I want to access some of the items in the order object after the session cleanup is closed, the nhibernate cannot delay loading the order item for us because the session is closed, and we write a test method to verify:
[Test] [ExpectedException (typeof (Lazyinitializationexception))]public void Lazyloadorderaggregateusingsessiononfailtest () { Order order = _relation. Lazyloadorderaggregateusingsession (2); String name = Order. Customer.Name.Fullname;}
The above test throws the "Could not initialize proxy-no Session" Expected Lazyinitializationexception exception, indicating that the test was successful and that the customer object of the order object could not be loaded.
4.n+1 Selection Questions
We access the product item after the order is loaded, causing the access to product to produce a selection statement for each item, and we use a test method to simulate the situation:
[test]public void Lazyloadorderaggregateselectbehaviortest () { Order order = _relation. Lazyloadorderaggregate (2); float sum = 0.0F; foreach (var item in order. Products) { sum + = Item. cost; } Assert.AreEqual (21.0F, sum);}
NHibernate generates SQL statements as follows:
SELECT order0_. OrderId as orderid1_0_, order0_. Version as version1_0_, order0_. OrderDate as orderdate1_0_, order0_. Customer as customer1_0_ from [Order] order0_ WHERE [email protected]; @p0 = ' 2 ' SELECT products0_. [Order] as order1_1_, products0_. Product as product1_, product1_. ProductId as productid3_0_, product1_. Version as version3_0_, product1_. Name as name3_0_, product1_. Cost as cost3_0_ from Orderproduct products0_ left outer join Product product1_ on products0_. Product=product1_. ProductId WHERE products0_. [Order] [Email protected]; @p0 = ' 2 '
I'm lucky this time, nhibernate. Automatically generates the most optimized query statement, loading two product objects in one breath. But imagine having a collection object with 100 items, and you just need to access one or two of them. This loading of all items is obviously a waste of resources.
Fortunately, NHibernate has a solution for these problems, which is to load immediately. If you want to know what happened afterwards, please listen to tell!
Go NHibernate Tour (12): A tentative study of lazy loading mechanism