I have a scenario where I am using nhibernate to map records from one table to several different derived classes based on a discriminator.
public class BaseClass { }
public class DerivedClass0 : BaseClass { }
public class DerivedClass1 : BaseClass { }
public class DerivedClass2 : BaseClass { }
I then use nhibernate's DiscriminateSubClassesOnColumn() method and alter the configuration to include
<subclass name="DerivedClass0" extends="BaseClass" discriminator-value="discriminator0" />
<subclass name="DerivedClass1" extends="BaseClass" discriminator-value="discriminator1" />
<subclass name="DerivedClass2" extends="BaseClass" discriminator-value="discriminator2" />
so that when mapped, these classes are cast to their derived classes and not BaseClass.
However, there are some records in my database which have a discriminator which does not have a corresponding subclass. In these cases, nHibernate throws an error:
"Object with id: 'xxx' was not of the specified subclass..."
Is there some way I can handle this, so that any records which do not have a corresponding subclass are cast to BaseClass rather than an error being thrown?
I have simplified the above as much as possible, however it is worth noting that the XML is edited dynamically which is why I am referencing fluent nhibernate [DiscriminateSubClassesOnColumn()] and XML at the same time.
The following things (which would help) are not an option:
I cannot correct the data to remove records which are invalid
I cannot create subclasses for those records which do not have one
I need to handle cases where nHibernate tries to map on a discriminator and finds that one does not exist.
The solution is to use the "AlwaysSelectWithValue()" method in the Fluent NHibernate mapping.
DiscriminateSubClassesOnColumn("discriminator").AlwaysSelectWithValue();
This forces NHIbernate to only fetch results from the database which have a corresponding subclass.
Related
I'm using Fluent NHibernate to map classes to a database and I'm using PersistenceSpecification.VerifyTheMappings() to verify the mappings in my unit tests.
If ClassA has a property of type ClassB and I want to verify the mapping, I first create an instance of ClassB then I try to use it with PersistenceSpecification like this:
ClassB classB = new ClassB();
new PersistenceSpecification<ClassA>(session)
.CheckProperty(x => x.ClassB, classB)
.VerifyTheMappings();
When I run the test in NUnit, the test fails with the following error:
System.ApplicationException : For property 'ClassB' expected 'MyNamespace.ClassB' of type 'MyNamespace.ClassB' but got 'ClassBProxyf24bc4...' of type 'MyNamespace.ClassB'
I also tried using "CheckReference" instead of "CheckProperty", but I got the same results. Creating the ClassB instance inline within CheckProperty() also didn't make a difference - not that I expected it to...
I've come across code examples on the web that imply that this should work. What am I missing here?
If ClassB is a mapped entity you should use CheckReference rather than CheckProperty.
However, the problem is that you have to help Fluent NHibernate decide if the objects are equal. You can either pass in an IEqualityComparer into the PersistenceSpecification or have your entities override the Equals method.
In the comparer / equals override you would probably want to do something like comparing the types and the primary key values.
There is a section at the Fluent NHibernate wiki about using PersistenceSpecification to test references, which includes a sample implementation of IEqualityComparer.
I'm having some trouble using nHibernate, automapping and a class structure using multiple chains of abstract classes
It's something akin to this
public abstract class AbstractClassA {}
public abstract class AbstractClassB : AbstractClassA {}
public class ClassA : AbstractClassB {}
When I attempt to build these mappings, I receive the following error
"FluentNHibernate.Cfg.FluentConfigurationException was unhandled
Message: An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.
Database was not configured through Database method."
However, if I remove the abstract keyword from AbstractClassB, everything works fine. The problem only occurs when I have more than one abstract class in the class hierarchy.
I've manually configured the automapping to include both AbstractClassA and AbstractClassB using the following binding class
public class BindItemBases : IManualBinding
{
public void Bind(FluentNHibernate.Automapping.AutoPersistenceModel model)
{
model.IncludeBase<AbstractClassA>();
model.IncludeBase<AbstractClassB>();
}
}
I've had to do a bit of hackery to get around this, but there must be a better way to get this working. Surely nHibernate supports something like this, I just haven't figured out how to configure it right.
Cheers,
James
Why do you include abstract classes in your AutoMappings, are they presented in the database too? Could you provide the inner exception Fluent throws?
model.IncludeBase<AbstractClassA>();
model.IncludeBase<AbstractClassB>();
With this in place you are trying to map AbstractClassB to the database, which is supposedly not what you want.
how exactly I can use public methods (non-virtual) with NHibernate?
I have this code:
public string crewNumber
{
get
{
return this.crewNumberField;
}
set
{
this.crewNumberField = value;
}
}
Note all my classes, properties, methods and interfaces are auto-generated and I do not want to change them manually.
Above code is producing this error:
The following types may not be used as
proxies: ... method get_crewNumber
should be 'public/protected virtual'
I see that it shold be possible to use simple public only properties here:
In our example above, we've made the
properties and the constructor public
- but that's not a requirement for NHibernate - it can use public,
protected, internal, or even private
properties to persist your data.
How do I turn off this virtual by default?
It's driving me crazy. I am really tempted here to drag one data adapter in visual studio and to end this ridiculous situation once and for all ;-)
Thanks
Specify that dynamic proxies should not be used for that class, by specifying lazy=false on the class-mapping.
Like this:
<class name="MyClass" table="MyTable" lazy="false">
</class>
This means offcourse that you cannot use dynamic proxies with NHibernate.
To be more clear:
- when you retrieve an instance of your class, which is able to use dynamic proxies, you'll recieve an 'empty instance'. That is, NHibernate will not fetch the data from the DB yet. You'll get an object who'se Id will be populated, but the other properties are not. Only when you access a property, then NHibernate will load the data from the DB. That's the reason why the properties need to be virtual, because NHibernate will create a subclass of your class internally, and override the properties so that it can achieve this behaviour.
I always specify 'lazy=false' on my class-mapping, since I don't want to have virtual properties for a reason that is infrastructure-related, instead of 'domain-related'.
(Note that this has nothing to do with lazy loading of associations; it is still possible to have them lazy loaded when you do not use dynamic proxies).
Put lazy="false" at the class mapping:
<class name="MyClass" table="MY_TABLE" lazy="false">
I have a scenario that i want to add some standard properties to my entities. Meaning that i will have e.g. 1 int and 2 string properties applied to all relevant entities. I have over 100 mapping files and most but not all will be hosts to these new properties. In the classes its easy to define this; in the mappings however i've found no reference other than creating a utility or xslt and applying that (How to define reusable <generator> elements in hibernate mapping).
However i want to be able to add/modify/remove properties from this "standard" mapping.
thx for any replies
Edit1: an example of the mapping i want to add
<property name="TimeOfEdit" column="TimeOfEdit" type="DateTime" not-null="true"/>
<many-to-one name="EditedBy" column="FK_EditedBy" cascade="save-update" not-null="true" />
Edit2:
I removed the accepted solution because with NH 2.1.1 XML Entities are not working (NH-1236) and NH will throw a "DTD is prohibited in this XML document"
It depends on how these properties are implemented in your classes.
If they are all defined in a base class or interface, you could map them once in the base class or interface, and derive using union-subclass. There are some limitations. Read this chapter in the NHibernate documentation about it.
If you decide to put them together into a class, you could map them as a user type. This will be similar to a component, but you could specify some things like type names, lengths and others in the user type. You still need to specify each column name.
There is another option: you could use XML entities. This is a rather primitive feature from XML which is supported by NHibernate. Read this chapter in the NH reference documentation where it is mentioned.
Creating a special code generator for your specific case is your only option.
Option 1:
-Define these 3 properties in a base class
-have your entities inherit from this base
-set up 'table per class hierarchy'
Option 2:
-Define these 3 properties as a component.
-You can have the mapping for these 3 properties in one file that is reused.
You might take a look at fluentNHibernate, It will simplify the mapping work for you. With With auto mapping you may only need an abstract base class to define these properties.
It seems that the only to do this, is to use Dynamic Mapping (http://ayende.com/Blog/archive/2008/05/01/Dynamic-Mapping-with-NHibernate.aspx)
as such since i've already defined an interface that my entities will use for the new properties (lets say IAuditable) its just a matter of running the appropriate code at the NH-session initialization
Configuration cfg = new Configuration() Mappings mappings = cfg.CreateMappings();
foreach (var persistentClass in mappings.Classes)
{
if (persistentClass.MappedClass is IAuditable)
{
...
}
}
and then
cfg.BuildSessionFactory();
to have it wired up and ready to be used
for about 85 classes the performance impact is negligible
What is the difference between lazy="true" and lazy="proxy" in nhibernate?
I suspect another way of thinking about it would be this.
class Foo
{
public virtual Bar SingleBar { get; set; }
public virtual ICollection<Bar> MultiBar { get; set; }
}
lazy="proxy" applies to single objects (ie foo.SingleBar)
lazy="true" applies to collections of objects (ie foo.MultiBar)
(You can't set lazy="proxy" to a collection, nor can you set lazy="true" to a single reference. Either will cause NH to throw a XmlSchemaException which is a little cryptic to beginners.)
Operationally they do the same abstract thing: when and only when the property is accessed does NHibernate hit the database and populate the property.
There is however a slight difference in the implementation due what is needed to fetch the objects (in the single case, the reference's id (Bar) was loaded with the parent entity (Foo). In the collection case, the ids are unknown and must be found in another table)
lazy="proxy" means that NHibernate will lazily initialize instances of your class;
When NHibernate retrieves an instance of your class from the database, it will - in this case - not return a 'real' instance of your class, but it will rather give you a proxy. That is, it will return an object that is of another type, more specifically, an object that is a subclass of your class (generated by NHibernate through IL generation).
The object that you will be given, is a proxy, and the only populated property, is the Id property. As soon as you call another property on the instance, NHibernate will initialize the proxy, and retrieve all the other properties / collections (except those that are lazy loaded) from the database.
Lazy="true" is used on another level. Whereas lazy="proxy" is used on the class-level, lazy="true" is used on the collection level. It means that the collection should be lazy loaded.
The documentation reference says that the value of the proxy attribute is in:
lazy="proxy|no-proxy|false"
lazy (optional - defaults to proxy): By default, single point associations are proxied.
lazy="no-proxy" specifies that the property should be fetched lazily when the instance variable is first accessed (requires build-time bytecode instrumentation).
lazy="false" specifies that the association will always be eagerly fetched.
By default, Hibernate3 uses lazy select fetching for collections and lazy proxy fetching for single-valued associations. These defaults make sense for most associations in the majority of applications.
http://docs.jboss.org/hibernate/stable/core/reference/en/html_single/#performance-fetching-lazy