NHibernate Warning

We are creating an ASP.NET MVC application that uses NH to access data. Using NH Profiler, I see a lot of warnings like "WARN: narrowing the proxy to Domain.CaseTask - this operation is aborted ==". I get this very often when I query for classes that appear in the table for each subclass, for example, using the NH Linq provider:

Query<ICaseTask>().Where(c => c.Assignee == Of || c.Operator == Of) 

where the CaseTask class inherits from Task, it triggers a warning.

Information about the warning on the Internet is scarce and basically hints that this is something that should be ignored ... What exactly warns about this for sure? Should this be something I have to fix?

+6
source share
2 answers

This warning applies to classes that have properties or fields that are a subclass. IE:

 public class Animal { public int Id {get;set;} } public class Cat : Animal { public int Weight {get;set;} } public class Person { public Cat Pet {get;set;} } 

NHibernate gets frustrated when it loads a human object because it does not want to drop for you because behavior becomes unpredictable. Unless you tell NHibernate how to work with Equals (among other logics), he will not know how to make this comparison on his own.

The main idea to fix this is to allow NHibernate to put the base class object in the graph, and then you are dealing with casting (note that this setting will use several slightly different mappings - do this to simplify the code, but it can obviously be done, saving properties as full getters / setters):

 public class Animal { public int Id {get;set;} } public class Cat : Animal { public int Weight {get;set;} } public class Person { private Animal _pet; public Cat Pet { get{return _pet as Cat;} } } 
+2
source

The reality is more complex. When you load an object using session.Load or you access a lazy resource, NHibernate returns a proxy object. This proxy object will be moistened (data will be downloaded from the database) the first time you access any of its properties. To achieve this, NHibernate generates a proxy class that extends the entity class and overrides all getters and seters properties. This works great when inheritance is not used, since you will not be able to distinguish between a proxy server and an entity class (base proxy class), for example. a simple proxy is MyEntity test will always work.

Now imagine that we have a Person object:

 class Person { // lazy-loaded public Animal Pet { get; set; } } 

And we also have a hierarchy of Animal classes:

 public abstract class Animal { ... } public class Cat { ... } public class Dog { ... } 

Now suppose the Pet property is loaded with laziness, when you request NHibernate for a personal pet, you will get a proxy object:

 var pet = somePerson.Pet; // pet will be a proxy 

But since Pet is a lazy loaded property, NH will not know if it will be a Cat or Dog instance, so he will do his best and create a proxy server that extends Animal . The proxy will run a test for pet is Animal , but will not run tests for pet is Cat or pet is Dog .

Now suppose you get access to some property of the Pet object, forcing NH to load data from the database. Now NH will know that your pet, for example, is a Cat , but the proxy server has already been generated and cannot be changed. This will force NHibernate to issue a warning that the original proxy for Pet , which extends the Animal type, will narrow to introduce Cat . This means that now the proxy object for animals with pet.Id , which you create using session.Load<Animal>(pet.Id) , will expand Cat from now on. This also means that since Cat now stored as part of the session, if we load the second person who shares the cat with the first, NH will use the already available Cat proxy instance to populate the lazy-load property.

One of the consequences will be that the reference to the Pet object will be different from the link received by session.Load<Animal>(pet.Id) (in the object.ReferencesEqual sense).

 // example - say parent and child share *the same* pet var pet = child.Pet; // NH will return proxy that extends Animal pet.DoStuff(); // NH loads data from DB var parent = child.Parent; // lazy-loaded property var pet2 = parent.Pet; // NH will return proxy that extends Cat Assert.NotSame(pet, pet2); 

Now that can harm you:

Therefore, the moral is to avoid as much inheritance as possible in your domain model.

+2
source

Source: https://habr.com/ru/post/902379/


All Articles