NHibernate: mapping user type object to a separate table - nhibernate

Let's start with this mapping:
<component name="Location">
...
<property name="Settings" type="JsonUserType,...">
<column name="LocationSettingsType" />
<column name="LocationSettingsData" />
</property>
</component>
This maps to
TABLE Primary (
...
LocationSettingsType,
LocationSettingsData
...
)
and
class Location {
...
object Settings { get; set; }
}
Now, I want to extract settings into a separate table (because they are seldom here).
So I get
TABLE Primary (
...
LocationSettingsId,
...
)
TABLE Settings (
Id,
Type,
Data
)
Can I keep my C# classes the same?
Update: This is not a many-to-one relationship. As before, each location has zero or one settings, and each settings belong to at most one location.

I believe the closest thing that exists to this is the <map> mapping element; details are explained in this article.

If you want a one to many relationship on the Primary and Settings tables, you'll have to set a foreign key constraint first. Then you'll use the bag property in XML to map your tables. You will have an entity for each table.
See also this question on NHibernate/FluentNHibernate Property Bag.
I also recommend you purchase the NHibernate 2 for Beginners book. It helped me alot.

This is an old question but i had the same issue and looking to a solution I came here.
the component element can map several columns to several object models.
the join element can map several tables to an object model.
The main problem is that while the component cannot map columns from a different table where the model belong, the join cannot map the different table columns to a different object model.
The solution I found is to use both to achieve the map column of a different table to several object:
<class name="Primary" table="Primary">
<id name="Id">
<generator class="identity"/>
</id>
<property name="Name" />
...
<join table="Settings">
<key column="PrimaryId"/>
<component name="Location">
...
<property name="Settings" type="JsonUserType,...">
<column name="LocationSettingsType" />
<column name="LocationSettingsData" />
</property>
</component>
</join>
</class>
Reference:
NHibernate Join mapping element
NHibernate Component mapping element

Related

Fluent NHibernate Complex Composite Key Mapping

I'm afraid to even ask this question really, as I find the whole thing pretty disgusting myself. But, what are you going to do with a legacy database.
I have the following three tables
Generator Alarm AlarmDescription
--------- ----- ----------------
Id Id
Id <- GensetId DescriptionText
EventTypeId -> AlarmCode
PanelId ----------------> PanelId
If it's not clear from the above rendering, I have an Alarm, which has both a Genset and an AlarmDescription. The Genset is directly mappable via the GensetId property. The AlarmDescription should also be easily mappable off the Id property right? But it wasn't designed that way, and instead is mapped off a composite of (AlarmCode, PanelId) (note, they don't even share the same field name, found this out after struggling to find any relation until inspecting the data).
So, how would you map this using Fluent NHibernate? I've tried a couple variations, but have failed. Something like the following would be ... ideal, but I don't think anything like this is necessarily directly available.
References(x => x.AlarmDescription)
.Column("AlarmCode", m => m.EventTypeId)
.Column("PanelId", m => m.Genset.PanelId)
Have you tried formulas? (Sorry, I am not using fluent.)
<many-to-one name="AlarmDescription">
<column name="EventTypeId" />
<formula>(select g.PanelId from Generator g where g.Id = GensetId)</formula>
</many-to-one>
This requires declaring AlarmDescription primary key as being the composite id (AlarmCode, PanelId).
If you need to preserve AlarmDescription id, then add in it a natural-id as a component:
<class name="AlarmDescription">
<id name="Id">
<generator .../>
</id>
<natural-id>
<component name="AlarmDescriptionNaturalId">
<property name="AlarmCode" />
<property name="PanelId" />
</component>
</natural-id>
...
And reference it as the key for your relation in Alarm thanks to property-ref:
<many-to-one name="AlarmDescription" property-ref="AlarmDescriptionNaturalId">
<column name="EventTypeId" />
<formula>(select g.PanelId from Generator g where g.Id = GensetId)</formula>
</many-to-one>

How to persist a subset of an object instead of the whole object?

I'm struggling with a NHibernate related problem where I could use some input.
Introduction:
I have a legacy database where the relational concepts have not really been applied.
In the database I have an OrderLine table which contains data for an order lines.
On top of that the table also contains all columns with Order specific information. This could for example be order number of a customer.
E.x. If i have 10 order lines - then I have 10 rows in my OrderLines table and each row has all the Order specific data e.g. order number or customer information.
I did not want to have the above structure in my code so a view was created for Orders so that I could map my Order in NHibernate which then has a set/bag of OrderLines which makes much more sense.
Mapping: (simplified)
<class name="Order" table="[view_Orders]">
<bag name="OrderLines">
</class>
<class name="OrderLine" table="OrderLines" />
The problem:
The complexity of the view makes it impossible to save to the view. When trying NHibernates throws this exception:
NHibernate.Exceptions.GenericADOException: could not insert: XXX ---> System.Data.SqlClient.SqlException: View or function 'view_Orders' is not updatable because the modification affects multiple base tables.
My NHibernate mapping is constructed as an Order object which has a "set or bag" of OrderLine objects. Ideally I would like NHibernate only to persist the set of OrderLine objects instead of the whole object.
Is there a way of achieving this? I have tried locking the object using different lock modes but it did not help me.
You can use mutable="false" to avoid the update and deletes as this article says:
Immutable classes, mutable="false", may not be updated or deleted by the application. This allows NHibernate to make some minor performance optimizations.
To avoid the insert you can use the following statement (Uses the proyection instead an insert command, dont forget use check="none"):
<sql-insert check="none">SELECT 1</sql-insert>
Here is a tested example:
<class name="Order" table="[view_Orders]" mutable="false">
<id name="OrderId" type="System.Guid">
<generator class="guid.comb"/> <!-- Change as you need -->
</id>
<!-- Other properties -->
<!-- <property name="GrandTotal"/> -->
<set name="OrderLines" lazy="true" inverse="true" cascade="all-delete-orphan">
<key column="OrderId"/>
<one-to-many class="OrderLine"/>
</set>
<sql-insert check="none">SELECT 1</sql-insert>
</class>
<class name="OrderLine" table="OrderLine">
<id name="OrderLineId" type="System.Guid">
<generator class="guid.comb"/> <!-- Change as you need -->
</id>
<!-- Other properties -->
<!-- <property name="OrderId"/>
<property name="GrandTotal"/>/> -->
</class>
In case I do understand your issue, the solution is surprisingly simple. We just would mark root object with dynamic-update="true"
<class name="Order" table="[view_Orders]" dynamic-update="true">
...
</class>
And then apply update="false" to every property or reference which we have in that Order class mapped to view:
...
<property name="Code" update="false"/>
...
<many-to-one name="Country" update="false />
But our collection will need the standard, even cascade mapping:
<class name="Order" table="[view_Orders]" dynamic-update="true">
<bag name="OrderLines"
lazy="true"
inverse="true"
batch-size="25"
cascade="all-delete-orphan" >
...
</bag>
... // other stuff is update="false"
</class>
And now code like this would do management of OrderLines, while not executing any updates on the root object Order
var session = ... // get ISession
// load root
var root = session.Get<Order>(123);
// if needed change existing line (pretend there is one)
root.OrderLines[0].Amount = 100;
// add new
var newOrder = ... // new order
root.OrderLines.Add(newOrder);
session.Save(root);
session.Flush();
And that is it. Cascade on the root object is doing what we need, while the update="false" is not updating it...
NOTE: Just interesting note - there is also class and collection
setting mutable="false", but it would not work here... as the
solution mentioned above (it is sad, because that would be more
elegant, but not working as expected...). See:
19.2.2. Strategy: read only
If your application needs to read but never modify instances of a persistent class, a read-only cache may be used. This is the simplest and best performing strategy. Its even perfectly safe for use in a cluster.
<class name="Eg.Immutable" mutable="false">

Nhibernate Cannot delete the child object

I know it has been asked for many times, i also have found a lot of answers on this website, but i just cannot get out this problem.
Can anyone help me with this piece of code?
Many thanks.
Here is my parent mapping file
<set name="ProductPictureList" table="[ProductPicture]" lazy="true" order-by="DateCreated" inverse="true" cascade="all-delete-orphan" >
<key column="ProductID"/>
<one-to-many class="ProductPicture"/>
</set>
Here is my child mapping file
<class name="ProductPicture" table="[ProductPicture]" lazy="true">
<id name="ProductPictureID">
<generator class="identity" />
</id>
<property name="ProductID" type="Int32"></property>
<property name="PictureName" type="String"></property>
<property name="DateCreated" type="DateTime"></property>
</class>
Here is my c# code
var item = _productRepository.Get(productID);
var productPictrue = item.ProductPictureList
.OfType<ProductPicture>()
.Where(x => x.ProductPictureID == productPictureID);
// reomve the finding item
var ok = item.ProductPictureList.Remove(productPictrue);
_productRepository.SaveOrUpdate(item);
ok is false value and this child object is still in my database.
Not 100% sure, but could be because you have defined ProductID as a property of ProductPicture, I assume this is the PK from the Product class. You don't need to add this again, it will be created by the relationship.
I'm not sure that your use of table="[ProductPicture]" in the set tag is right.
The one-to-many tag already establishes the link between ProductPictureList and ProductPicture.
I think the table attribute is generally for using a separate relationship table when modelling many-to-may relationships.
From nhibernate.info Doc:
table (optional - defaults to property name) the name of the
collection table (not used for one-to-many associations)
And:
A collection table is required for any collection of values and any
collection of references to other entities mapped as a many-to-many
association

Bidirectional one to many (or many to one) cascade delete behaviour. It works, but why?

I have two Nhibernate mappings for two classes, Category and Product. My Category class has two properties that are collections. The Children property is a collection of type Category which represents child categories (represents a category menu, typical parent child scenario). The second property on the Category class is a Products collection which represents all the products under a category.
What I am trying achieve is when I delete a category I want the category to deleted but not the product. So I want the product to be orphaned. i.e have its foreign key (CategoryId) in the Product table set to null. I don't want to delete a product just because I have deleted a category. I want to be able to reassign in at a later time to another category. My mappings representing the mentioned scenario are below.
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="naakud.domain" namespace="naakud.domain">
<class name="Category">
<id name="Id">
<generator class="hilo" />
</id>
<version name="Version"/>
<property name="Name" not-null="true" unique="true" />
<set name="Products"
cascade="save-update"
inverse="true"
access="field.camelcase-underscore">
<key column="CategoryId" foreign-key="fk_Category_Product" />
<one-to-many class="Product" />
</set>
<many-to-one name="Parent" class="Category" column="ParentId" />
<set name="Children"
collection-type="naakud.domain.Mappings.Collections.TreeCategoriesCollectionType, naakud.domain"
cascade="all-delete-orphan"
inverse="true"
access="field.camelcase-underscore">
<key column="ParentId" foreign-key="fk_Category_ParentCategory" />
<one-to-many class="Category"/>
</set>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="naakud.domain" namespace="naakud.domain">
<class name="Product">
<id name="Id">
<generator class="hilo" />
</id>
<version name="Version" />
<property name="Name" not-null="true" unique="true" />
<property name="Description" not-null="true" />
<property name="UnitPrice" not-null="true" type="Currency" />
<many-to-one name="Category" column="CategoryId" />
</class>
</hibernate-mapping>
With this mapping, when I delete a category which has products associated with it I get the following constraint error.
The DELETE statement conflicted with the REFERENCE constraint "fk_Category_Product". The conflict occurred in database "naakud", table "dbo.Product", column 'CategoryId'.
The statement has been terminated.
However, when I remove the inverse=true attribute on the Products collection in the Category mapping then it works fine. My CategoryId foreign key in the products table is set to null and thus disassociating a product with a category. Which is what I want.
I have read about the inverse attribute and I understand it signifies the owning side of a relationship and updates/inserts/deletes are done in a different order which is why I think it solves my problem. So my question is, am I solving my problem in the correct way? How does this affect performance? (not much I suspect). Would it be better to have a uni-directional relationship without the many to one side and have the inverse attribute set to true to get better performance? Or am I going crazy and completely missing the point?
Another way of fixing the delete problem is by setting the many-to-one property to null on all the related entities to null before flushing.
I can think of at least two ways to do it:
In the same method that calls session.Delete(category), do:
foreach (var product in category.Products)
product.Category = null;
Using HQL:
session.CreateQuery(
"update Product set Category = null where Category = :category")
.SetParameter("category", category)
.ExecuteUpdate();
Update:
Here's a proof-of-concept implementation using an event listener.
I assume that you read about Inverse Attribute in NHibernate
As the error message says, your DELETE generates a conflict with the foreign key constraint, meaning that the DB cannot delete the Category as long as there are Products referencing that particular Category.
What you could do (if you can alter the DB schema) is applying "ON DELETE SET NULL" to your foreign key constraint. That way, when the DELETE is executed, the DB will automatically set all references in the Product table to NULL.
If you cannot modify the foreign key, then you would have little choice but to remove the inverse attribute. Doing so will result in NHibernate first setting the Product.Category reference to NULL and then deleting the Category.
If you need Product.Category fairly often then you should not get rid of the many-to-one attribute in Product.
Regarding the performance, that depends on how often you insert Products. Each insert will result in an additional update to set the foreign key. That should not be a problem, though.

NHibernate many to many mapping error - NHibernate.MappingException: Could not determine type for:

I am having a problem when trying create a many to many mapping. Consider the following tables:
CREATE TABLE [dbo].[student]
(
[Id] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR(255) NOT NULL,
-- Some other stuff...
)
CREATE TABLE [dbo].[Subject]
(
[Id] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (50) NOT NULL,
-- Some other stuff...
)
CREATE TABLE [dbo].[studentToSubject]
(
[studentId] INT NOT NULL,
[subjectId] INT NOT NULL,
)
The interesting part of my student mapping file looks like this:
<id name="Id" type="Int32">
<column name="Id" sql-type="int" not-null="true" unique="true"/>
<generator class="native" />
</id>
<property name="Name" not-null="true" />
<bag name="subjects" table="studentToSubject">
<key column="studentId"></key>
<many-to-many column="subjectId" class="subject" />
</bag>
I want to end up with a student with a collection of their subjects. However, I get an error:
NHibernate.MappingException: Could not determine type for: MyApp.Domain.Subject, MyApp.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=865c2d2b185d0c4b, for columns: NHibernate.Mapping.Column(studentId).
I have seen some examples of this type of mapping, but they differ in the fact that their Id columns have name that match the mapping table name, for example their Id column in the student table is called 'studentId'. I cannot do this (it has to be Id) but I think this is the cause of the problem.
Thanks
you should write this relation for subject class again and sure your field for relation is correct.
i do it with attribute models
It seems like you are either missing the mapping file for Subject (did you remember to include it properly?) or you need to provide the full path if it is in a different namespace.
Please correct me if I'm wrong, but I guess there's something messy about your Id mapping. Perhaps it can be done the way you do and I have never seen it, this is possible.
Though I would write my mapping like so:
<class name="Student"> <!-- I omit the table attribute as both your class and table seems to have the same name. -->
<id name="Id">
<generator class="native"/> <!-- Though I would recommend using "identity" if SQL Server's used. -->
</id>
<property name="Name" length="255" not-null="true"/>
<list name="Subjects" not-null="true" table="StudentToSubject">
<key column="studentId" />
<many-to-many column="studentId" class="Subject" />
</list>
</class>
Within the element, it is optional to specify the not-null, unique, type and sql-type attributes as NHibernate will determine them during runtime using reflection, though I understand that for pedagogy purposes, it is better to write those. Plus, if you want your Id property name within your object class be the same as your table field, you may just omit the column attribute. NH will then consider using the same name as the property for the data table field Id field.
As for your collection of subjects, if you intend to use a Dictionary in your Sudent class, you'd better the element instead of . However, if you want a List, you'd better opt for the element as I did. This all depends on your needs and your objective through this exercise.
Please, consider that I took this NH XML mapping right from the top of my head, and I didn't test it, so it might contain errors on fly.
In addition to this, you can take an eye out on this: Chapter 6. Collection Mapping
Hope this helps! =)
Did you remember to set the .hbm.xml mapping files to an Embedded Resource?
Also this line is not correct.
<many-to-many column="subjectId" class="subject" />
Subject should be capital S and it is good practice to give the namespace and assembly. such as
<many-to-many column="subjectId" class="MyApp.Domain.Subject, MyApp.Domain" />
I might be mistaken but the error hints at it:
NHibernate.MappingException: Could not determine type for: MyApp.Domain.Subject, MyApp.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=865c2d2b185d0c4b, for columns: NHibernate.Mapping.Column(studentId).
Basically the way i read the error, NHibernate can't figure out what type the column studentId is, The fault is most likely in your Subject mapping. There is a property there which apperently references a student (i'm guesing the other side of the many-to-many).