I'm trying to map a set of joined-subclass entities to a parent entity. The SQL being produced by NHibernate seems to be incorrect. Am I missing anything in my mapping? Is there another way I can approach this problem?
<class name="ResultItem" table="result">
<id name="ID">
<generator class="identity" />
</id>
<many-to-one name="Job" column="JobID"/>
<property name="Timestamp"/>
<many-to-one name="User" column="UserID"/>
<joined-subclass name="ResultItemAttachment" table="result_attachment">
<key column="ID"/>
<property name="Comment"/>
</joined-subclass>
</class>
This is the SQL being generated by NHibernate. It seems as if its getting confused between super and sub class members? The only table with JobID is the result table and not result_attachment.
SELECT attachment0_.JobID as JobID1_,
attachment0_.ID as ID1_,
attachment0_.ID as ID26_0_,
attachment0_1_.JobID as JobID26_0_,
attachment0_1_.`Timestamp` as Timestamp26_0_,
attachment0_1_.UserID as UserID26_0_,
attachment0_.`Comment` as Comment33_0_
FROM result_attachment attachment0_
inner join result attachment0_1_ on attachment0_.ID=attachment0_1_.ID
WHERE attachment0_1_.JobID=?;
Thanks in advance
I'm afraid this is currently a bug in NHibernate (in there since 2.1 :|) apperently there is a fix in the current alpha of 3.2
https://nhibernate.jira.com/browse/NH-1747
Possible work around is to manually fetch the bag at runtime. Hardly ideal, other option would be to try and get the alpha version running but running an alpha in a production environment is hardly a great idea.
Related
I am mapping the following entities using NHibernate:
+ Party (abstract)
- Employee
- Customer
I am using the mapping strategy called: joined-subclass in the following way:
<!-- Base PARTY entity-->
<class name="PartyMap" abstract="true" table="Party">
<id name="Id" column="PartyID">
<generator class="guid.comb" />
</id>
<joined-subclass table="Customer" name="Customer">
<key column="CustomerID" />
</joined-subclass>
<joined-subclass table="Employee" name="Employee">
<key column="EmployeeID" />
</joined-subclass>
</class>
My problem is that inside the Party table I have the following structure:
PartyTable
PartyID
EmployeeID
CustomerID
While NHibernate use the Id field for every child table mapped. Should I use a different approach like component to achieve my goal?
One possible solution that I have found is to implement an event listner on top of NHibernate framework so that every time an entity is saved I can control the values passed and fix the error with the Guid without the need to create crazy Stored Procedures.
I know it's ugly but the database is legacy so there is not really much I can do
I have been having a lot of trouble with deadlocks. I've received some really useful feedback that suggested this may be a side effect of my use of identity which is a regular id. My application is of reasonable size. 20-30 entities. Making a major change like this is quite a scary proposition. So would be very grateful for some feedback
1) what would i need to do to change to hilo. This application has quite a lot of data. Would i need to do some kind of data migration.
2) is hilo the correct choice, would guid be an easier upgrade.
An example entity mapping. I'm using nhibernate 2
<class name="Post" table="Post">
<id name="Id" type="Int32" column="Id" unsaved-value="0">
<generator class="identity"/>
</id>
<many-to-one name="Company" column="CompanyId" class="EStore.Domain.Model.Company, EStore.Domain" />
<many-to-one name="Retailer" column="RetailerId" class="EStore.Domain.Model.Retailer, EStore.Domain" />
<many-to-one name="Parent" column="ParentId" class="EStore.Domain.Model.Post, EStore.Domain" />
<many-to-one name="PostStatus" column="PostStatusId" class="EStore.Domain.Model.PostStatus, EStore.Domain" />
</class>
highlow needs a source for high (table or sequence) and calculates a lowvalue.
you need a sequence/table which value * maxlowvalue(the value you define in the mapping) is greater than the highest id in your database/table(if you give each table a different highvalue sequence/table)
I am trying to develop my very first project with Nhibernate 3.0.
I've gone through loads of material (blogs, papers and samples) and I think I can understand the basics, pretty much.
I think I've understood the meaning of different types of collection but than when I see the examples found on the Internet I think I haven't really understood.
The documentation says that you should use a Set when you do not want duplicates and a List/Bag when you want to allow duplicates.
Most of the samples I have found are based on a typical situation where you have Orders/OrderLines.
If I have a look the mapping file of the Order I can see something like this:
<class name="OrderHeader"
table="Orders">
<id name="OrderId">
<generator class="hilo"/>
</id>
<property name="OrderDate"/>
<bag name="OrderItems" table="OrderDetails" cascade="all" inverse="true">
<key column="OrderId"/>
<one-to-many class="OrderDetail"/>
</bag>
</class>
<class name="OrderDetail"
table="OrderDetails">
<id name="DetailId">
<generator class="hilo"/>
</id>
<many-to-one name="ProductOrdered" column="ProductId"/>
<many-to-one name="Order" column="OrderId" />
</class>
I had expcted to see the OrderItems mapped as a Set; an order will have unique OrderItems?
Am I right?
At the same time I would expect to find a mapping for the class Product a bag of OrderItems
...
<bag lazy="true" name="OrderItems">
<key foreign-key="FK_OrderItems_Products">
<column name="ProductCode" />
</key>
.....
</bag>
...
In this situation a product would have a list of non-unique OrderItems.
Is there anything am I missing?
Forgive me all for the silly question :-s
I would set it as a <list ...> as in my book two orderlines with the same characteristics are identical (.Equals should return true) - also, many consider the order(!) of orderlines to be important. :-)
The reason for this is that bag mapping is compatible with a .NET IList<T> mapping as Yads answered. Collections are typically mapped that way to avoid having to reference Iesi.Collections in your classes.
With NHibernate 2.1, you can use set mapping by declaring the collection as ICollection<T> and initializing it as a HashSet<T>. Using NHibernate 3 I believe you can declare the collection as ISet<T>.
I agree most real world collections should be mapped as sets.
The reason most people implement it as a bag is because they can use the built in List<> class or IList<> interface to represent their collection.
I have an NHibernate object that is a superclass (let's call it "Super"), and a subclass that inherits from it (let's say it's called "Sub").
<class name="Super" table="SuperThings">
<id name="Id" type="System.Int32" column="SuperId">
<generator class="identity" />
</id>
<joined-subclass name="Sub" table="SubThings" extends="Super" lazy="true">
<key column="SubId" />
</joined-subclass>
</class>
I have a separate class (called "Widget") with a property of type Super.
<class name="Widget" table="Widgets" lazy="true">
<id name="Id" type="System.Int32" column="NoteId">
<generator class="identity" />
</id>
<many-to-one name="SuperProperty" column="SuperId" class="SuperClass" />
</class>
When I access SuperProperty on an instance of a Widget, NHibernate attempts to lazily load it, but I get this error:
More than one row with the given identifier was found: 1, for class: Super
There is only one record in SuperThings with an id of 1, and a separate record in SubThings associated to it. After using the NHibernate Profiler and debugging my code, it looks like NHibernate is trying to instantiate an object whose type is the subclass.
Why is it doing that? Is there something wrong with how I'm thinking this should be mapped?
Obviously, this is a simplified version of what I'm actually working with. The objects I'm working with have many more properties of different types, so maybe I've left out what's actually causing the problem, but I wanted to make sure that I'm understanding things on a basic level at least.
If there is a record in SuperThings with Id=1, and one record in SubThings with SubId=1, according to your mapping you have a Sub instance persisted, so NHibernate is right when it tries to instantiate it.
If this is not what you intended, you should reread Chapter 8. Inheritance Mapping to see the alternatives.
I have two classes: Family and Address.
A family has a physical address and a mailing address.
The mapping file for Family looks like:
....
<id name="Id" column="Id" type="Int32" unsaved-value="0">
<generator class="native"></generator>
</id>
<many-to-one name="PhysicalAddress" class="Address" column="PhysicalAddressId" cascade="all" unique="true" />
<many-to-one name="MailingAddress" class="Address" column="MailingAddressId" cascade="all" unique="true" />
...
The mapping file for Address looks like:
...
<id name="Id" column="Id" type="Int32" unsaved-value="0">
<generator class="native"></generator>
</id>
<property name="StreetAddress1" column="StreetAddress1" />
<property name="StreetAddress2" column="StreetAddress2"/>
<property name="City" column="City" />
<property name="State" column="State" />
<property name="ZipCode" column="ZipCode" />
...
(Note that Family-PhysicalAddress and Family-MailingAddress are one-to-one relationships.)
What I would like to happen is that when I execute
aFamily.MailingAddress = null;
session.Save(aFamily);
session.Flush();
I expect NHibernate to automatically delete the mailing address record from SQL Server for me.
BUT, that doesn't happen. NHibernate does not delete the address record from SQL Server.
Is there any way I can make it work?
Thank you!
This behaviour isn't supported by NHibernate. Of course the problem is that you probably don't have access to the NHibernate session in your domain logic where the change is made.
One possible -- though admittedly not ideal solution -- is to simply run another process to clean up orphaned entities.
Here is a discussion of this scenario:
http://colinjack.blogspot.com/2008/03/nhibernate-gotchas-orphans-and-one-to.html
And a link to a ticket on the issue:
https://nhibernate.jira.com/browse/NH-1262
Unfortunately NHibernate currently does not support automatic deletions of orhphans for many-to-one (Hibernate v3 in Java does support it). It is only supported on lists (cascade="all-delete-orphan").
What you can try to do is to use component mapping. Maybe it is possible to embed many-to-one into a component.
But I think it would better to explicitly delete the related object.