NHibernate narrowing proxy warning - nhibernate

We are building an ASP.NET MVC application utilizing NH for data access. Using NH Profiler I see a lot of warnings like "WARN: Narrowing proxy to Domain.CaseTask - this operation breaks ==". I get these very often when executing queries for classes which are mapped in a table per subclass, for example, using the NH Linq provider:
Query<ICaseTask>().Where(c => c.Assignee == Of || c.Operator == Of)
where the class CaseTask inherits from Task, triggers the warning.
Information about the warning in the internet is scarce and mostly hints that this is something to be ignored... What does this warning warn about exactly? Should this be something I should seek to correct?

The reality is more complicated. When you load entity using either session.Load or you access a property that is lazy loaded NHibernate returns a proxy object. That proxy object will by hydrated (data will be loaded from DB) when you access any of its properties for the first time. To achieve this NHibernate generates proxy class that extends entity class and overrides all property getters and setters. This works perfectly when inheritance is not used since you will have no way to differentiate between proxy and entity class (proxy base class), e.g. simple test proxy is MyEntity will always work.
Now imagine that we have a Person entity:
class Person {
// lazy-loaded
public Animal Pet { get; set; }
}
And we also have Animal class hierarchy:
public abstract class Animal { ... }
public class Cat { ... }
public class Dog { ... }
Now assume that Pet property is lazy loaded, when you ask NHibernate for person pet you will get a proxy object:
var pet = somePerson.Pet; // pet will be a proxy
But since Pet is lazy loaded property NH will not know if it will be instance of a Cat or a Dog, so it will do its best and will create a proxy that extends Animal. The proxy will pass test for pet is Animal but will fail tests for either pet is Cat or pet is Dog.
Now assume that you will access some property of pet object, forcing NH to load data from DB. Now NH will know that your pet is e.g. a Cat but proxy is already generated and cannot be changed.
This will force NHibernate to issue a warning that original proxy for pet that extends type Animal will be narrowed to type Cat. This means that from now on proxy object for animal with pet.Id that you create using session.Load<Animal>(pet.Id) will extend Cat from now. This also means that since Cat is now stored as a part of session, if we load a second person that shares cat with the first, NH will use already available Cat proxy instance to populate lazy-loaded property.
One of the consequences will be that object reference to pet will be different that reference obtained by session.Load<Animal>(pet.Id) (in 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 when this may cause harm to you:
When you put your entities into Sets or Dictionaryies in your code or if you use any other structure that requires Equals/GetHashCode pair to work. This can be easily fixed by providing custom Equals/GetHashCode implementation (see: http://www.onjava.com/pub/a/onjava/2006/09/13/dont-let-hibernate-steal-your-identity.html?page=1)
When you try to cast your proxy object to target type e.g. (Cat)pet, but again there are know solutions (e.g. Getting proxies of the correct type in NHibernate)
So the moral is to avoid as much as possible inheritance in your domain model.

This warning is about classes having 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 upset when it loads the person entity because it doesn't want to cast for you because behavior becomes unpredictable. Unless you tell NHibernate how to deal with Equals (among other logic) it won't know how to do that comparison on its own.
The basic idea to correct this is to let NHibernate put the base class object into the graph and then you deal with the casting (note that this setup would use some slightly different mappings - ive done this to simplify the code but it can obviously be done by keeping the 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;}
}
}

Related

Create object of one type from object of another type with database lookups

I have an application that gets a car entity from a third party database. I call the entity ThirdPartyCar. My application needs to create a Car entity by using data from a ThirdPartyCar. However, the Car entity must also derive some of its data from my application's database. For example, a status of a ThirdPartyCar might be _BOUGHT and through a database lookup my application must transform to Sold.
I currently have a Car constructor that has a ThirdPartyCar argument. But the Car constructor cannot populate the lookup data since it is an entity and entities should not have a reference to a repositories. So, I also have a service to populate the remaining data:
public class ThirdPartyCar {
#Id
private Long id;
private String vin;
private String status;
// more props + default constructor
}
public class Car {
#Id
private Long id;
private String vin;
private CarStatus status;
// more props (some different than ThirdPartyCar) + default constructor
public Car(ThirdPartyCar thirdPartyCar) {
this.vin = thirdPartyCar.getVin();
// more props set based on thirdPartyCar
// but props leveraging database not set here
}
public class CarStatus {
#Id
private Long id;
private String status;
}
public class CarBuilderService {
private final CarStatusMappingRepository repo;
public Car buildFrom(ThirdPartyCar thirdPartyCar) {
Car car = new Car(thirdPartyCar);
CarStatus status = repo.findByThirdPartyCarStatus(thirdPartyCar.getStatus());
car.setStatus(status);
// set other props (including nested props) that depend on repos
}
}
The logical place to create a Car based on a ThirdPartyCar seems to be the constructor. But I have a disjointed approach b/c of the need of a repo. What pattern can I apply such that all data is created in the constructor but still not have the entity be aware of repositories?
You should avoid linking two POJO classes from different domains in constructor. These two classes should not know anything about each other. Maybe they represent the same concept in two different systems but they are not the same.
Good approach is creating Abstract Factory interface which will be used everywhere where Car should be created from ThirdPartyCar:
interface ThirdPartyCarFactory {
Car createNewBasedOn(ThirdPartyCar source);
}
and one implementation could be your RepositoryThirdPartyCarFactory:
class RepositoryThirdPartyCarFactory implements ThirdPartyCarFactory {
private CarStatusMappingRepository repo;
private CarMapper carMapper;
public Car createNewBasedOn(ThirdPartyCar thirdPartyCar) {
Car car = new Car();
carMapper.map(thirdPartyCar, car);
CarStatus status = repo.findByThirdPartyCarStatus(thirdPartyCar.getStatus());
car.setStatus(status);
// set other props (including nested props) that depend on repos
return car;
}
}
In above implementation you can find CarMapper which knows how to map ThirdPartyCar to Car. To implement this mapper you can use Dozer, Orika, MapStruct or your custom implementation.
Other question is how you got ThirdPartyCar object. If you load it by ID from ThirdPartyRepository you can change your abstract factory to:
interface CarFactory {
Car createNew(String id);
}
and given implementation loads by ID ThirdPartyCar and maps it to Car. Everything is hidden by factory which you can easily exchanged.
See also:
Performance of Java Mapping Frameworks

Fluent NHibernate HasMany relation with different subtypes of same superclass

I´m using Fluent Nhibernate with automapping and having problem setting up a bi-directional HasMany relationship because of my current inheritance.
I simplified version of my code looks like this
public abstract class BaseClass
{
public BaseClass Parent { get; set; }
}
public class ClassA : BaseClass
{
public IList<ClassB> BChilds { get; protected set; }
public IList<ClassC> CChilds { get; protected set; }
}
public class ClassB : BaseClass
{
public IList<ClassD> DChilds { get; protected set; }
}
public class ClassC : BaseClass
{
}
public class ClassD : BaseClass
{
}
Every class can have one parent and some parents can have childs of two types. I´m using table-per-type inheritance which result in the tables
"BaseClass"
"ClassA"
"ClassB"
"ClassC"
"ClassD"
To get a working bi-directional mapping I have made the following overrides
(one example from ClassA)
mapping.HasMany<BaseType>(x => x.BChilds).KeyColumn("Parent_Id");
mapping.HasMany<BaseType>(x => x.CChilds).KeyColumn("Parent_Id");
This works fine on classes with only one type of children, but ClassA with two child types will get all subtypes of BaseType in each list which ofcourse will end up in an exception. I have looked at two different workarounds tho none of them feels really sufficient and I really believe there is a better way to solve it.
Workaround 1: Point to the concrete subtype in the HasMany mapping. (Updated with more info)
mapping.HasMany<ClassB>(x => x.BChilds).KeyColumns("Parent_Id");
(BaseType replaced with ClassB)
With this mapping NHibernate will in some cases look in the ClassB table for a column named Parent_Id, obviously there is no such column as it belongs to the BaseClass table. The problem only occurs if you add a statement based on BChilds during a ClassA select. e.g loading an entity of ClassA then calling ClassA.BChilds seems to work, but doing a query (using NhibernateLinq) something like
Query<ClassA>().Where(c => c.BChilds.Count == 0)
the wrong table will be used. Therefore I have to manually create a new column in this table with the same name and copy all the values. It works but it´s risky and not flexible at all.
Workaround 2: Add a column to the BaseClass that tells the concrete type and add a where statement to the HasMany mapping.
(after my update to workaround1 I´m no longer sure if this could be a workable solution)
By adding a column they same way as it´s done when using table-per-hierarchy inheritance with a discriminatorValue. i.e BaseType table will get a new column with a value of ClassA, ClassB... Tho given how well NHibernate handles the inheritance overall and by reading the NHibernate manual I believe that the discriminator shouldn´t be needed in a table-per-type scenario, seems like Nhibernate already doing the hardpart and should be able to take care of this in a clean way to without adding a new column, just can´t figure out how.
What's your base class mapping and what does your subclass map look like?
You should be able to do
mapping.HasMany(x => x.BChilds);
And with the correct mapping, you shouldn't have a problem.
If it's fluent nhibernate, look into
UseUnionSubclassForInheritanceMapping();

Mapping inheritance in NHibernate 3.3

I have the inheritance described below :
public abstract class BaseEntity<TId> {....}
public abstract class ModelEntity : BaseEntity<Int32>{....}
public abstract class AuditableEntity : ModelEntity,IAuditable{....}
public class ApplicationUser : AuditableEntity{....}
public class SuperUser : ApplicationUser
I am using NHibernate 3.3 and I want to Create the mappings for that inheritance
public abstract class ModelEntityMap<TEntity> : ClassMapping<TEntity>
where TEntity : ModelEntity
{...}
public class AuditableEntityMap<TEntity> : ModelEntityMap<TEntity> where TEntity : AuditableEntity
{ ...}
public class ApplicationUserMap : AuditableEntityMap<ApplicationUser>
{...}
public class SuperUserMap : JoinedSubclassMapping<SuperUser>{...}
When the application starts and trys to set up the database it raises the following Exception :
Ambiguous mapping for SuperUser More than one root entities was found BaseEntity / ApplicationUser
Possible solutions
-Merge the mapping of root Entity in the one is representing the real root in the hierarchy
-Inject a IModelInspector with a logic to discover the real root-entity.
I was using Fluent nhibernate with the same inheritance and worked fine with SuperUserMap defined as
public class SuperUserMap : SubClassMap {...}
I am new to Nhibernate mapping by code and quite confused !!!
I believe there are two ways to solve this problem:
a) Using the concept of discriminator that identifies the type of the class stored and thereby the right object is retrieved from the database, in this case your class is mapped to a table that has all the columns plus the discriminator columns. Not sure how this works with multi-level inheritance but this is something that you can google.
b) take a look at this post on how he deals with inheritance: http://fabiomaulo.blogspot.co.nz/2011/04/nhibernate-32-mapping-by-code_13.html you might get some idea to solve your issue.
You can influence the decision whether an entity is a root entity by overriding the IsRootEntity logic of the model mapper that you use to create mappings.
Here's an example that defines the default NHibernate mapping-by-code behaviour:
var modelMapper = new ConventionModelMapper();
modelMapper.IsRootEntity((type, declared) =>
{
if (declared) return true; // Type has already been declared as root entity
return type.IsClass
&& typeof(object) == type.BaseType
&& modelMapper.ModelInspector.IsEntity(type);
});
You will have to tweak this decision logic to exclude the BaseEntity class as possible root entity.
I had this error with NHibernate 4.1.1 (May 2017), so I'm answering with how I solved it for future reference
In my case, I copied an existing mapping of an inheriting class, and forgot to change the parent mapping class to ClassMapping and encountered the same error
In other words, in your mapping class, check the parent class, make sure it is ClassMapping or JoinedSubclassMapping if it's a child class

Fluent NHibernate: the entity '(method name)' doesn't have an Id mapped.

This is my first time trying Fluent NHibernate and Auto mapping. Unfortunately I have run into an issue that I cannot get past. I'm getting an error saying that a method on one of my classes cannot be mapped.
public class Person
{
public IEnumerable<string> GetStuff(){return stuff;}
}
The Exception Message is:
The entity '<GetStuff>d__0' doesn't have an Id mapped.
I even tried adding an IAutoMappingOverride to ignore the method (using map.IgnoreProperty).
Is it really trying to map a method? whats going on here?
Every entity that you want to Automap must have an Id property, or inherit from a class that has an Id property. Your Person class does neither.
Also, in my experience, all public methods in entities must be declared virtual (though this may not be required if you eager load everything).
I got around this by manually marking each Entity with an interface.
public class MyAutomappingConfiguration : DefaultAutomappingConfiguration
{
public override bool ShouldMap(Type type)
{
return type.GetInterfaces().Contains(typeof (IEntity));
}
}

AutoMapping Custom Collections with FluentNHibernate

I am retrofitting a very large application to use NHibernate as it's data access strategy. Everything is going well with AutoMapping. Luckily when the domain layer was built, we used a code generator. The main issue that I am running into now is that every collection is hidden behind a custom class that derives from List<>. For example
public class League
{
public OwnerList owners {get;set;}
}
public class OwnerList : AppList<Owner> { }
public class AppList<T> : List<T> { }
What kind of Convention do I have to write to get this done?
I don't think you're going to be able to achieve this with a convention. You will have to create an auto mapping override and then do the following:
mapping.HasMany(l => a.owners).CollectionType<OwnerList>();