I have a baseclass that IS NOT abstract and two classes that is based on this class but which have different implemenations in how they calculate the result. The baseclass also inherits from an abstract class that is shared in many different places in the system so I cannot really change that one.
I know that I could extract a baseclass that all three inherits from and just use a normal mapping with subclasses but I just want to know if it is possible to create a hbm file that maps this scenario.
class BaseClass : CalculationBaseClass
{
public virtual int Calculate()
{
...
}
}
class SpecializedClass : BaseClass
{
public override int Calculate()
{
...
}
}
class HistoricClass : BaseClass
{
public override int Calculate()
{
...
}
}
From NHibernate documentation:
NHibernate supports the three basic inheritance mapping strategies.
table per class hierarchy
table per subclass
table per concrete class
You would choose one of the strategies based on what you current table structure is, or if you don't have legacy schema you can just choose the one that is most appropriate for you object model (based on mapped properties for example). In your case, if you use 'table per class hierarchy' you would end up with mapping like this:
<class name="CalculationBaseClass" table="MyTable">
<id name="Id" type="Int64" column="ID">
<generator class="native"/>
</id>
<discriminator column="TYPE" type="String"/>
<subclass name="BaseClass" discriminator-value="BASE">
...
</subclass>
<subclass name="SpecializedClass" discriminator-value="SPECIALIZED">
...
</subclass>
<subclass name="HistoricClass " discriminator-value="HISTORIC">
...
</subclass>
</class>
Related
I have a class hierarchy:
Public MustInherit Class SystemSetting
Public Property System As Integer
Public Property Sequence As Integer
Public Property Description As String
Public Property Notes As String
End Class
Public MustInherit Class SystemSetting(Of T)
Inherits SystemSetting
Public MustOverride Property Value As T
End Class
Public NotInheritable Class StringBasedSystemSetting
Inherits SystemSetting(Of String)
Public Overrides Property Value As String
End Class
I have a mapping:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="SystemSettings"
namespace="SystemSettings"
default-lazy="false">
<class xmlns="urn:nhibernate-mapping-2.2"
name="SystemSetting"
abstract="true">
<composite-id>
<key-property name="System" column="SystemId"/>
<key-property name="Sequence" column="SettingSeq"/>
</composite-id>
<discriminator column="SettingType" not-null="true" force="false"/>
<property name="Description" column="SettingDescription"/>
<property name="Notes" column="SettingNotes"/>
<subclass name="StringBasedSystemSetting" discriminator-value="T">
<property name="Value" column="SettingText"/>
</subclass>
</class>
</hibernate-mapping>
This mapping creates the correct schema and allows me to successfully save and flush an object. However, when I query, via LINQ or QueryOver, I get the exception:
Cannot instantiate abstract class or interface
I can resolve this by removing the abstract nature of the SystemSetting class. However, I don't want to compromise my class design if possible. Why is NH trying to create instances of SystemSetting when my mapping is clear on its abstract nature and uses a type discriminator?
Update:
If I replace the composite Id with an assigned Id it works.
I found the answer to this. When a composite Id is used, NH has to use instances of the mapped class to represent the Id. This is why it was trying to instantiate a SystemSetting regardless of the 'abstract' mapping attribute.
Changing the design so that the composite Id is represented as its own type fixes the problem. My base class is still abstract and my queries now work.
Why can't NHibernate access a property inherited from an abstract base class. When I try to use the property in a QueryOver in the Where clause I'm getting
could not resolve property: ID of: TheWorkshop.Web.Models.Customer
var customer = Session.QueryOver<Customer>()
.Where(c=>c.ID ==id)
.SingleOrDefault<Customer>();
Intelisense helped me build the query and the solution compiles, so there is an ID property on the Customer class. The ID property on Customer is inherited from an abstract Contact class that in turn inherits from a DomainEntity<T> which exposes a protected field.
public abstract class DomainEntity<T>
{
protected Guid _persistenceId;
//...
}
public abstract class Contact : DomainEntity<Contact>
{
public virtual Guid ID
{
get { return _persistenceId; }
}
public virtual Address Address
{
get { return _address; }
set { _address = value; }
}
//...
}
and in the mapping file
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="TheWorkshop.Web"
namespace="TheWorkshop.Web.Models"
default-access="field.camelcase-underscore"
default-lazy="true">
<class name="Contact" table="Contacts" abstract="true">
<id name="_persistenceId" column="ID" type="Guid" access="field"
unsaved-value="00000000-0000-0000-0000-000000000000">
<generator class="guid.comb" />
</id>
<!-- ... -->
<union-subclass name="Customer" table="Customers">
Following the answer to a similar question I updated to NHibernate 3.3.3-CR1 from NHibernate 3.3.2.4000 but I still have the same issue.
The problem was that NHibernate couldn't infer from my mapping how to resolve the ID property. So although the classes compiled fine and the _persistenceId property on the abstract base class could be accessed through a getter on the implementing classes, because of the mismatch in names between _persistenceId and ID NHibernate wasn't able to follow that.
The (easier) solution was to change my names to match up. There is a harder solution which involves implementing the IProperyAccessor, IGetter and ISetter interfaces and in order to provide a path to pass the string ID in order to use the ClassName access strategy.
The simpler of the two solutions was just to rename _persistenceId to _id (and update all the references to it) so
<id name="_persistenceId" column="ID" type="Guid" access="field"
unsaved-value="00000000-0000-0000-0000-000000000000">
becomes
<id name="Id" column="Id" type="Guid"
unsaved-value="00000000-0000-0000-0000-000000000000">
Note I was also able to drop the access="field" in the updated id mappings
We have a BaseEntity of which all our other domain classes inherit. On this BaseEntity are some basic properties. This could be something like DateLastChange for example.
We're using NHibernate with hbm mapping files. I'm trying to avoid having to map DateLastChange in every mapping file.
I found this post by Ayende, which makes me believe I could use union-subclass to achieve this (see his last approach). However, he includes a table name for his abstract class, that isn't in his table-schema.
<class name="Party"
abstract="true"
table="Parties">
...
Does the table have to exist, or will NHibernate just ignore this attribute? And can I then omit it?
This is not needed. As per the documentation (thanks to kalki):
<class name="Payment">
<id name="id" type="long" column="PAYMENT_ID">
<generator class="sequence"/>
</id>
<property name="amount" column="AMOUNT"/>
...
<union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
<property name="creditCardType" column="CCTYPE"/>
...
</union-subclass>
<union-subclass name="CashPayment" table="CASH_PAYMENT">
...
</union-subclass>
<union-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
...
</union-subclass>
</class>
And:
If your superclass is abstract, map it with abstract="true". If it is
not abstract, an additional table (it defaults to PAYMENT in the
example above), is needed to hold instances of the superclass.
I have the following abstract class in fluentnhibernate:
public abstract class EntityMapping<TEntity> : ClassMap<TEntity> where TEntity : EntityBase
{
protected EntityMapping()
{
Id(x => x.Id, "Id")
.UnsavedValue("00000000-0000-0000-0000-000000000000")
.GeneratedBy.GuidComb()
.Index("IX_Lookup");
OptimisticLock.Version();
Version(x => x.Version);
Map(x=>x.DateLastChange); // your column
}
}
all other mappings use the abstract class:
public SomeEntityMap:EntityMapping<SomeEntity>{
public SomeEntityMap(){
Map(x=>x.SomeProperty);
}
}
class FooBase{...}
class FooDerived : FooBase {...}
class BaseContainer
{
public virtual FooBase Foo {get;set;}
}
class DerivedContainer : BaseContainer
{
public virtual new FooDerived Foo {get;set;}
}
Hibernate mapping options
Option 1 below
Fails to persist on a/c of NHibernate generating additional member declaration in the xml (index out of range error)
<class name="BaseContainer" discriminator-value="0">
<discriminator column="ContainerType" type="int" />
<many-to-one name="Foo"
foreign-key="..."
class="FooBase"
column="FooId"
unique="true"/>
<subclass name="DerivedContainer" discriminator-value="1">
<many-to-one name="Foo"
foreign-key="..."
class="FooDerived"
column="FooId"
unique="true"/>
</subclass>
</class>
Option 2 independent mappings !
Fetch operation erroneous, does not discriminate the types
<class name="BaseContainer" discriminator-value="0">
<discriminator column="ContainerType" type="int" />
<many-to-one name="Foo"
foreign-key="..."
class="FooBase"
column="FooId"
unique="true"/>
</class>
<class name="DerivedContainer" discriminator-value="1">
<many-to-one name="Foo"
foreign-key="..."
class="FooDerived"
column="FooId"
unique="true"/>
</class>
Stuck, would be grateful for any pointers, although I understand this can easily achieved if done via table per subclass, is there any way above can be achieved via table per class hierarchy
I'm looking to create a many to many relationship using NHibernate. I'm not sure how to map these in the XML files. I have not created the classes yet, but they will just be basic POCOs.
Tables
Person
personId
name
Competency
competencyId
title
Person_x_Competency
personId
competencyId
Would I essentially create a List in each POCO for the other class? Then map those somehow using the NHibernate configuration files?
You can put the many-to-many relation to either class, or even to both. This is up to your domain model. If you map it to both, one of them is inverse.
class Person
{
// id ...
IList<Competency> Competencies { get; private set; }
// you domain model is responsible to manage bidirectional dependencies.
// of course this is not a complete implementation
public void AddCompetency(Competency competency)
{
Competencies.Add(competency);
competency.AddPerson(this);
}
}
class Competency
{
// id ...
IList<Person> Persons { get; private set; }
}
Mapping:
<class name="Person">
<id ....>
<bag name="Competencies" table="Person_x_Competency">
<key column="personId"/>
<many-to-many class="Competency" column="competencyId"/>
</bag>
</class>
<class name="Competency">
<id ....>
<bag name="Persons" table="Person_x_Competency" inverse="true">
<key column="competencyId"/>
<many-to-many class="Person" column="personId"/>
</bag>
</class>
Only make it bidirectional if you really need it.
By the way: it is much better to write the classes first and create the database design afterwards. The database can be exported from the mapping files. This is very useful.