I know that all members of a POCO class for NHibernate must be defined as virtual, and in EF (code first), you only need to set the collection / reference objects as virtual for lazy loading.
So if I want to create POCO objects that are compatible with both EF and NH should I just declare every member of my POCO classes as virtual??
The reason for wanting this is that we're currently evaluating both EF and NHibernate ORM's and if we end up changing our plans down the road, we don't want to have to update our POCO's
EF needs virtual navigation properties for lazy loading but it also uses virtual scalar/complex properties for dynamic change tracking so if you mark all properties as virtual it will be correct approach.
Anyway do you evaluation upfront. virtual properties will be minimal issue if you decide to change ORM later - you will find much harder problems.
Actually you're not forced to declare every property as virtual in NH. If you turn-off the lazy load behaviour ('on' by default) you no longer need to declare all those "virtuals", and may specify case-by-case which properties are lazy-loaded.
So, if you want, you may have a POCO with just reference objects as virtual in both NH and EF.
Sidenote: Anyway, and just for the effort of it, I would declare all properties as virtual and be done with it :)
Or alternatively, if you create an interface or abstract base for your POCO's, you can use the <class name="MyPoco" proxy="IMyPoco"/> attribute in NHibernate which also eliminates the need for virtual properties, since NH then defers to creating its subclasses from the proxy rather than from your POCO directly.
Related
I am working in a project that's work with N Hibernate. Due to performance issues and increasing in complexity of the project we need to do association manually in our code.As we all know for that we have to set lazy property true. What i want know that, is their any way to do association with set lazy property true.We have already created our own methods for filling Association.But still for that also we need to write many queries and code which is not satisfactory.
Please let me know some way for this.
Thanks.
Lazy loading is turned on by default. There is basically two ways how lazy loading is implemented by NHibernate.
Lazy loading of collections
Lazy loading of "single ended" references (many-to-one)
Collections are easy and straight forward. NHibernate uses its own implementation if the collection classes anyway, lazy loading is implemented there.
Single ended references ("normal" associations) are not that easy. Lazy loading is implemented in a proxy. The proxy is a class created at runtime which inherits from the referenced class. That's why everything in the referenced class needs to be virtual. The proxy overrides every member and makes sure that the data is loaded when a member is accessed from outside. The problem with the proxy is, if you reference a base class, you get a proxy from the base class and you can't downcast it to the real class. So be careful when using lazy loading with inherited classes.
Lazy is turned on by default, you need to explicitly turn it off. So you don't need to do anything special to get lazy loading.
When you are optimizing performance, also consider to use batch-fetching.
for single ended associations:
<class name="xx" batch-size="10">
and on collections:
<bag name="xx" .... batch-size="10">
it reduces the N+1 problem a lot (by factor of 10 in this example.).
I have a situation where I have a Common.Domain.Person and Specific.Domain.Person.
First one should be provided as a part of a common package.
Second one appears when common package has to be customized to fit the needs of specific project.
In the object model, it can be easily implemented with inheritance.
In the NH mapping, however, I have encountered a small problem.
I can create an NHibernate <subclass> mapping, but that would require me to use an discriminator. However, I know that if specific person class was inherited, then common class instances will never be used within this specific project.
What is the best way to implement this without adding discriminator column to the base class (since there are no different cases to discriminate)?
this is what i wanted and nhibernate supports it using xml entities. Unfortunately this feature has been borked since (at least) NH v2++.
see also Using Doctype in Nhibernate
A work-around could be to inject these properies programmaticaly when you create the SessionFactory (Dynamic Mapping)
see also http://ayende.com/Blog/archive/2008/05/01/Dynamic-Mapping-with-NHibernate.aspx
Just map the Specific.Domain.Person and leave Common.Domain.Person unmapped.
If you are not saving instances of it, NHibernate does not need to know about it.
I dig a lot of things about the DDD approach (Ubiquitous language, Aggregates, Repositories, etc.) and I think that, contrary to what I read a lot, entities should have behavior rather then being agnostic. All examples I see tend to present entities with virtual automatic properties and an empty constructor (protected or worst, public) and that's it. I consider this kind of objects more like DTOs then entities.
I'm in the process of creating a framework with its specific API and I don't want to be tied to an ORM. So I built the domain first (without thinking of persistence) and now I would like to use NHibernate as persistence tool so I added a new project to my current solution to help ensure that my model isn't altered to support NHibernate. This project should be an implementation of the abstract repositories that live inside my domain. And now the difficulties arise.
Since it is my first time with NHibernate (I'm also trying Fluent Nhibernate but it seems even more restricting) I would like to know :
Is it possible to use NHibernate without altering a DDD model that is part of a framework
The things (constraints) that are necessary for NHibernate to work as expected and efficiently (virtual properties, empty constructors, etc.) I think this list would be helpful to a lot of people who are starting to learn NHibernate.
Please keep in mind that I'm building a framework so the Open/Closed Principle is very important for me.
P.S.: Sorry if my english is not good, I'm from Montreal and I speak french.
Edit 1: Here is one problem I have with NHibernate now - How to map Type with Nhibernate (and Fluent NHibernate)
For NHibernate:
All mapped classes require a default (no-arguments) constructor. The default constructor does not have to be public (it can be private so that it is not a part of the API), but it must exist. This is because NHibernate must be able to create an instance of the mapped class without passing any arguments. (There are workarounds, but don't do that.)
All mapped properties for which lazy-loading will be required must be marked virtual. This includes all reference properties and all collection properties. This is because NHibernate must be able to generate a proxy class deriving the mapped class and overriding the mapped property.
All mapped collection properties should use an interface as the property type. For example, use IList<T> rather than List<T>. This is because the collections types in the .NET Framework tend to be sealed, and NHibernate must be able to replace a default instance of the collection type with its own instance of the collection type, and NHibernate has its own internal implementations of the collection types.
For NHibernate, prefer Iesi.Collections.Generic.ISet<T> to System.Collections.Generic.IList<T>, unless you are sure that what you want is actually a list rather than a set. This requires being conversant in the theoretical definitions of list and set and in what your domain model requires. Use a list when you know that the elements must be in some specific order.
Also note that it's typically not easy to swap object-relational mapping frameworks, and in many cases it is impossible, when you have anything beyond a trivial domain model.
The short answer to your question is that it is not possible, but if don't need lazy loading the required alterations are trivial.
No matter what, you will have add default constructors to classes that do not already have them. If you are willing to forgo lazy-loading, those default constructors can be private, and you don't have to make any other changes to your domain model to use NHibernate.
That's awfully close to persistence ignorance.
Having said that, if you want lazy-loading, you'll need to make several changes (outlined in other answers to this question) so that NHibernate can create proxies of your aggregated entities. I'm personally still trying to decide whether lazy-loading is an enabling technology for DDD or if it's a premature optimization that requires too many intrusive changes to my POCOs. I'm leaning toward the former, though I really wish NHibernate could be configured to use a specific constructors.
You might also take a look at Davy Brion's blog (I particularly liked Implementing A Value Object With NHibernate), which is really illuminating if you're interested in domain-driven-design and avoiding anemic domain models.
In my experience, the only thing that NHibernate requires of a domain is virtual properties and methods and a default no-argument constructor, which as Jeff mentioned, can be marked private or protected if need be. That's it. NHibernate is my OR/M of choice, and I find the entire NHibernate stack (NHibernate, NHibernate Validator, Fluent NHibernate, LINQ to NHibernate) to be the most compelling framework for persisting POCO domains.
A few things you can do with NHibernate:
Decorate your domain model with NHV attributes. These constaints allow you to do three things: validate your objects, ensure that invalid entities are not persisted via NHibernate, and help autogenerate your schema when using using NHibernate's SchemaExport or SchemaUpdate tools.
Map your domain model to your persistent storage using Fluent NHibernate. The main advantage, for me, in using FNH is the ability to auto map your entities based on conventions that you set. Additonally, you can override these automappings where necessary, manually write class maps to take full control of the mappings, and use the xml hbm files if you need to.
Once you buy into using NH, you can easily use the SchemaExport or SchemaUpdate tools to create and execute DDL against your database, allowing you to automatically migrate domain changes to your database when initilizing the NH session factory. This allows you to forget about the database, for all intents and purposes, and concentrate instead on your domain. Note, this may not be useful or ideal in many circumstances, but for quick, local development of domain-centric apps, I find it convenient.
Additionally, I like using generic repositories to handle CRUD scenarios. For example, I usually have an IRepository that defines methods for getting all entites as an IQueryable, a single entity by id, for saving an entity, and for deleting an entity. For anything else, NH offers a rich set of querying mechanisms -- you can use LINQ to NHibernate, HQL, Criteria queries, and straight SQL if need be.
Th only compromise you have to make is using NHV attributes in your domain. This is not a deal breaker for me, since NHV is a stand-alone framework which adds additional capabilities if you choose to use NHibernate.
I have built a few apps using NH, and each has a persistence ignorant domain with all persistence concerns separated into its own assembly. That means one assembly for your domain, and another for your fluent mappings, session management, and validation integration. It's very nice and clean and does the job well.
By the way: your English is pretty darn good, I wish my French was up to par ;-).
Just to put my two bits in, I struggled with the same thing once but I overcame this by:
Adding protected default constructor to every entity.
Making Id virtual
Let's take for example upvote and downvote for Vote entity on my experiment website:
http://chucknorrisfacts.co.uk/ (NHibernate + MySQL with Mono)
public class Vote : Entity
{
private User _user;
private Fact _fact;
// true: upvote, false: downvote
private bool _isupvoted;
// for nHibernate
protected Vote() { }
public Vote(User user, Fact fact, bool is_upvoted)
{
Validator.NotNull(user, "user is required.");
Validator.NotNull(fact, "fact is required.");
_fact= fact;
_user = user;
_isupvoted = is_upvoted;
}
public User User
{
get { return _user; }
}
public Fact Fact
{
get { return _fact; }
}
public bool Isupvoted
{
get { return _isupvoted; }
}
}
This class inherits from Entity where we stick all the minimum necessary for Nhibernate.
public abstract class Entity
{
protected int _id;
public virtual int Id { get {return _id;} }
}
and Fluent mapping where you Reveal the private property.
public class VoteMap : ClassMap<Vote>
{
public VoteMap()
{
DynamicUpdate();
Table("vote");
Id(x => x.Id).Column("id");
Map(Reveal.Member<Vote>("_isupvoted")).Column("vote_up_down");
References(x => x.Fact).Column("fact_id").Not.Nullable();
References(x => x.User).Column("user_id").Not.Nullable();
}
}
You could probably place protected default constructor in Entity class and configure nHibernate to use it instead but I didn't look into it yet.
I'm attempting to map an entity hierarchy using NHibernate almost all of which have events. When attempting to build a session factory however, I get error messages similar to the following:
Core.Domain.Entities.Delivery: method
remove_Scheduled should be virtual
Delivery is an entity in my domain model with an event called Scheduled. Since events cannot be declared virtual I'm at a loss as to how to proceed here. Why would NHibernate need events to be virtual?
Public members must be declared virtual if you use lazy loading because NHibernate will create proxy objects for your entities at runtime. So do not use lazy loading or just declare the event as virtual - that is not so common, but it is possible.
NHibernate creates proxy classes for all lazy loaded entities and uses them where an entity is referenced but not yet loaded. Accessing this proxy triggers loading the real entity from the database. This approach requires to inherit from your entity class at runtime and override the public members hence this members to be virtual.
And there is another solution. You can add proxy="ISomeInterface" to the class declaration. Then you do not need virtual members while proxys just implement the given interface.
I have experienced the same problem with implementing INotifyPropertyChanged on my lazy loaded objects. The problem is that you actually deal with two different .NET instances so that when you fire the NPC event in your real instance you will not receive it from any reference to the proxy. Making it virtual allows the proxy to 'forward' this event. Unfortunately defining events as virtual/overridable is not possible in VB.NET (2005) and hence we had to introduce a C# project with a base class implementing only these virtual events just to get around the VB issue. see also https://forum.hibernate.org/viewtopic.php?f=25&t=990162&start=0
If there are other ways I would be keen to know myself since our method makes proxies a bit less transparant than they should be. Also in the area of auto reconnecting the session when lazy loaded objects need to be initialized seem a bit of a pain.
Regards,
Theo
how does your mapping look like ?
Did you map an event ?
I haven't encountered this issue before, but, then again, I always specify the 'lazy=false' attribute on my class mapping, so that my properties don't have to be declared as virtual. (Since i do not like to declare properties as virtual, if my business model doesnt requires this)
<class name="MyClass" table="MyTable" lazy="false">
</class>
I have some entity types that I would like to lazy load. However, they have some internal (assembly) fields they expose, but are not used outside that class. These fields are compiler generated (F#) and I cannot change them. The an example exception is:
NHibernate.InvalidProxyTypeException:
The following types may not be used as
proxies: Mappings.MTest: field id#47
should not be public nor internal
I understand why NHibernate is doing this, and how having fields, if I accessed them, would mess up the lazy-loading properties of the proxies that are generated. However, since I know I won't be using the fields, can I override NHibernate somehow?
Is there any way I can say "ignore this field"? I'm using Fluent NHibernate, if that makes it easier.
Edit: I should also note, I'm using NHibernate 2.1.0 Alpha 2.
Edit2: The main gist here is that I want to keep LazyLoading enabled, which means I have to use the proxy generation. Disabling LazyLoading works (no proxies), but sorta defeats the purpose of a nice framework like NHibernate.
I reassembled NHibernate (easier than getting the source and rebuilding) and removed the code that errors on internal/public fields. LazyLoading appears to work just fine without that check. (Although, I'm new to NHibernate and so there are probably scenarios I don't know about.)
Edit:
Ah, there is a property, "use_proxy_validator" that will disable all validation checks. Good enough.
Fluently.Configure()
.ExposeConfiguration(fun cfg ->
cfg.Properties.Add("use_proxy_validator", "false"))...
Just set the lazy property to false,
<class name="OrderLine" table="OrderLine" lazy="false" >
you can read more in:
Must Everything Be Virtual With NHibernate? - http://davybrion.com/blog/2009/03/must-everything-be-virtual-with-nhibernate/
Ofir,
www.TikalK.com
You can use the
[XmlIgnore]
attribute to decorate the fields :)
Can you use an Interface to declare the fields "used" ?http://nhibernate.info/doc/nh/en/index.html#persistent-classes-poco-sealed
"Another possibility is for the class to implement an interface that declares all public members"
I don't know if NH use the same #transient annotation/attribute as the JAVA version to ignore a property in persistent operations.
You might want to take a look at this page which gives an overview of using F# with Fluent NHibernate.
Edit I just noticed your username. Am I correct in perhaps thinking that this is your blog? How foolish of me. It does seem to address your problem though, specifically "We start off by disabling LazyLoad because most of the properties are not virtual, and NHibernate will fail to validate the mapping. Instead, we explicitly LazyLoad things, like the Store reference."? Maybe I'm just misunderstanding the problem.