views:

419

answers:

3

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?

A: 

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>
Frederik Gheysels
I didn't even think it was possible to map an event. You always specify lazy = false? The thing is lazy loading is an absolute must in my situation. Specifying what entities to load in every situation would be prohibitive.
Jimit
I specify lazy=false on the class level. By doing so, I do not have to create my properties virtual when I do not want to.The drawback is that NHibernate does not use dynamic proxies when retrieving objects: for instance, with dynamic proxies, when retrieving an object, NHibernate will only populate the Id of the object. Only when you access one of the properties of the object, the entire object will be loaded.This does NOT affect lazy loading of collections however.
Frederik Gheysels
A: 

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.

Daniel Brückner
The domain model is written in VB.NET. You can't declare events as virtual (Overridable) in VB as far as I know.
Jimit
I understand the requirement for virtual members, I can't see why NHibernate would need events to be virtual. The add_* and remove_* methods of an event are there simply to add and remove handlers of the event. They don't access state and so no need to be virtual.
Jimit
I've checked the source code for NHibernate and it seems the ProxyTypeValidator.CheckAccessibleMembersAreVirtual(System.Type type, IList errors) is where the error occurs. The method just checks for all methods of class, except for GetType and validates that they're virtual.
Jimit
Would using an interface as the proxy class mean other entities that refer to the persistent class should declare the reference in terms of the interface? Eg. if I have an Order class implementing IOrder and I use IOrder as the proxy interface, would Customer.Orders have to be of type IList<IOrder>?
Jimit
I never used this approach but I would exspect this, too.
Daniel Brückner
+1  A: 

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&amp;t=990162&amp;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

related questions