My problem is that i have two entities (Document and Attach) that has an relationship one-to-one. In my app, i can save first the Document and lately if i want, i can attach an archive to it, that will be on the table Attach.
The error occurs when i have an object Document already inserted in database and then i try to add an attach on it.
Below is the nhibernate mapping:
Document.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Sigre.Business"
namespace="Sigre.Business.BusinessEntity">
<class name="Document" lazy="false" table="grsds.documento_fcdr">
<id name="Code" type="int" unsaved-value="0" column="docf_sq_documento_fcdr">
<generator class="sequence">
<param name="sequence">grsds.sq_docf_sq_documento_fcdr</param>
</generator>
</id>
<property name="Nome" type="AnsiString" length="100" not-null="true" column="docf_nm_documento_fcdr" />
<many-to-one name="Manifest" class="TransportManifest" column="mtra_sq_manifesto_transporte" not-null="false" cascade="none" />
<many-to-one name="User" class="User" column="user_id" not-null="false" cascade="none" />
<set name="Attach" inverse="false" lazy="false" cascade="save-update">
<key column="docf_sq_documento_fcdr" />
<one-to-many class="Attach" />
</set>
</class>
</hibernate-mapping>
Attach.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="Sigre.Business"
namespace="Sigre.Business.BusinessEntity">
<class name="Attach" lazy="false" table="grsds.espec_documento_fcdr">
<id name="Code" type="int" unsaved-value="0" column="docf_sq_documento_fcdr">
<generator class="foreign">
<param name="property">Document</param>
</generator>
</id>
<property name="Archive" column="esdf_mm_documento_fcdr" type="BinaryBlob" not-null="true" />
<one-to-one constrained="true" name="Document" access="property" />
</class>
</hibernate-mapping>
If i am inserting both Document and Attach together, it works. But when i have a Document created and try to insert an Attach, the following error occurs:
ORA-01407: cannot update ("GRSDS"."ESPEC_DOCUMENTO_FCDR"."DOCF_SQ_DOCUMENTO_FCDR") to NULL
What i tried:
1 - Save the Document having the attach to insert:
bmDocument.Save(document);
Ok i solved this question.
When i bring the object Document from database, the attribute Attach when has no Attach, come as an empty list: {}
When i tried to add an Attach to this Document, i was overwriting the reference, like this:
Document.Attach = new List() { new Attach() };
The solution was use the method Add of the list that was brought from the database:
Document.Attach.Add( new Attach() );
Related
I am working with an Oracle legacy database and I am trying to map a relationship with two tables. Unfortunately the company who designed the database used composite keys.
I've got this table (ORDERS) which has a primary key composed on 3 fields: ordernumber (number), version and company.
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="BpSalesOrders.Domain"
namespace="BpSalesOrders.Domain">
<class name="Order" table="OCSAORH" mutable="false" where="OCHAMND = 0">
<cache usage="read-only"/>
<composite-id>
<key-property name="Number" column="OCHORDN" type="String" length="10"></key-property>
<key-property name="Ver" column="OCHAMND" type="Int32"></key-property>
<key-property name="Company" column="OCHCOSC" type="String" length="5"></key-property>
</composite-id>
<property name="Reference" column="OCHOCNO" type="String" length="25"></property>
<property name="Date" column="OCHOCDT" type="Int32"></property>
<property name="Status" column="OCHSTA1" type="Char"></property>
<property name="LineOfCreditStatus" column="OCHSTA4" type="Char"></property>
<property name="WareHouse" column="OCHRESP" type="String"></property>
<set name="OrderLines" access="field.pascalcase-underscore" inverse="true" lazy="true" mutable="false">
<key>
<column name="OCLORDN" not-null="true"/>
<column name="OCLAMND" not-null="true" default="0"/>
<column name="OCLCOSC" not-null="true"/>
</key>
<one-to-many class="OrderLine" not-found ="ignore"/>
</set>
<set name="OrderReleases" access="field.pascalcase-underscore" inverse="true" lazy="true" mutable="false">
<key>
<column name="ORLORDINE" not-null="true" />
<column name="ORLSOCIETA" not-null="true"/>
</key>
<one-to-many class="OrderRelease" not-found ="ignore"/>
</set>
</class>
</hibernate-mapping>
There's a relation with OrderLines which works fine cause that table has the same exact key structure.
I am having problem with the OrderReleases relation. That table has got a primary key composed on a OrderNumber, Company and date. There's no version here:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="BpSalesOrders.Domain"
namespace="BpSalesOrders.Domain">
<class name="OrderRelease" table="OCBPORDRIL" mutable="true">
<composite-id>
<key-property name="Company" column="ORLSOCIETA" type ="String" length="5"></key-property>
<key-property name="OrderNumber" column="ORLORDINE" type ="String" length="10"></key-property>
<key-property name="RequestDate" column="ORLDATARICHIESTA" type ="Int32"></key-property>
</composite-id>
<property name="Status" column="ORLSTATUS" type="Char" length="1"></property>
<property name="StatusMessage" column="ORLSEGNALAZIONE" type="String" length="90"></property>
<property name="ProcessingDate" column="ORLDATAELABORA" type ="Int32"></property>
</class>
</hibernate-mapping>
Considering that the relationship is one-to-many I would like to join the table Orders and OrderRelease on OrderNumber and Company. If I try to do that (as in the example) nHibernate throws an exception telling me that the key it's trying to map is composed with 3 fields.
Is there a way to create an non-existing column which wouldn't be persisted so that I can setup my mapping and relations?
Any help will be apreciated.
Ended up creating a view with a fake column.
I have a tree structure mapped to the data base in a table like this:
UID numeric(18, 0)
NodeUID varchar(50)
Text nvarchar(50)
TreeLevel int
ParentUID varchar(50)
OrderInLevel int
IsLeaf bit
It is an old table and I cannot change it so bear with me...
The NodeUID is a GUID.
the ParentUID column is mapped to the NodeId of a different row.
A root node has a value of "0" in its ParentUID column.
I am trying to map the Tree with NHibernate like this:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="BasicFW.Core.Domain.NavigationTree.UsersNavigationTreeNode, BasicFW.Core" table="bDoxTreeNodes" lazy="false" schema="bDox.dbo">
<id name="NodeUId">
<column name="NodeUID"/>
<generator class="assigned"/>
</id>
<property name="Text">
<column name="Text"/>
</property>
<property name="TreeLevel">
<column name="TreeLevel"/>
</property>
<property name="IsLeaf">
<column name="IsLeaf"/>
</property>
<many-to-one name="Parent" class="BasicFW.Core.Domain.NavigationTree.UsersNavigationTreeNode, BasicFW.Core" column="ParentUID" not-found="ignore"/>
<bag name="Children" lazy="false" order-by="OrderInLevel ASC" cascade="all-delete-orphan" inverse="true">
<key column="ParentUID"/>
<one-to-many class="BasicFW.Core.Domain.NavigationTree.UsersNavigationTreeNode, BasicFW.Core" />
</bag>
</class>
</hibernate-mapping>
The thing is that when I try to update a node ( and a root node in specifies ) the Parent property is null and so NHibernate try`s to Update the ParentUID column to null, and so it failles since to column will not accept null.
thanks
Can you create a trigger for that table? If yes, you could perhaps create a trigger that fires before update/insert. Something like:
create trigger TreeNode_before before insert, update
on TreeNode
referencing NEW as _new
for each row
begin
if _new.ParentUID is null then
set _new.ParentUID = '0';
end if;
end;
Edit: An alternative would be using an interceptor. I have not used that myself but according to the following question it should work in your case, too.
Edit: fixed the link.
NHibernate write value = NULL when ID < 0
I have found the correct mapping that worked, here is the mapping for my tree.
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="BasicFW.Core.Domain.NavigationTree.UsersNavigationTreeNode, BasicFW.Core" table="TreeNodes" lazy="false" >
<id name="NodeID">
<column name="NodeUID"/>
<generator class="assigned"/>
</id>
<property name="Text">
<column name="Text"/>
</property>
<property name="TreeLevel">
<column name="TreeLevel"/>
</property>
<property name="ParentID" >
<column name="ParentUID" />
</property>
<property name="IsLeaf">
<column name="IsLeaf"/>
</property>
<many-to-one name="Parent" class="BasicFW.Core.Domain.NavigationTree.UsersNavigationTreeNode, BasicFW.Core" column="ParentUID" not-found="ignore" update="false" insert="false"/>
<bag name="Children" lazy="false" order-by="OrderInLevel ASC" inverse="true" cascade="all-delete-orphan">
<key column="ParentUID"/>
<one-to-many class="BasicFW.Core.Domain.NavigationTree.UsersNavigationTreeNode, BasicFW.Core"/>
</bag>
</class>
</hibernate-mapping>
I have disabled the update and insert in the Parent property.
the database has two table,one is mb_user table and other is mb_comment table。A user have some comments.When I insert a comment into mb_comment ,the comment_user_id of mb_comment is null.I can't save value of comment_user_id.Please help me!
Map file
mb_user Map file
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="MiserBlogData" namespace="MiserBlogData.Entities" default-lazy="false">
<class name="A_Person" table="mb_user" discriminator-value="0">
<id name="Id" column ="user_id" >
<generator class ="native"/>
</id>
<discriminator column="user_role" type="int" />
<property name="State" column="user_state" />
<property name ="Name" column="user_name" />
<property name ="Pwd" column="user_pwd" />
<property name ="CDate" column="user_cdate" />
<property name ="UDate" column="user_udate" />
<property name ="Role" column="user_role" />
<property name ="Face" column="user_face" />
<bag name="CommentList" >
<key column="comment_user_id" foreign-key="FK_PersonComment" />
<one-to-many class="Comment" />
</bag>
</class>
</hibernate-mapping>
mb_comment Map file
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="MiserBlogData" namespace="MiserBlogData.Entities">
<class name ="Comment" table="mb_comment">
<id name="Id" column ="comment_id">
<generator class ="native"/>
</id>
<property name ="ArticleId" column="comment_article_id" />
<property name ="Content" column="comment_content" />
<property name ="State" column="comment_state" />
<property name ="CDate" column="comment_cdate" />
<many-to-one name="Person" column="comment_user_id" class="A_Person" not-null="true" foreign-key="FK_PersonComment" />
</class>
</hibernate-mapping>
C# code
protected ISession _session = NHibernateHelper.GetCurrentSession();
public virtual object Save<T>(T obj) where T : class
{
return _session.Save(obj);
}
error :not-null property references a null or transient valueMiserBlogData.Entities.Comment.Person
I know,if I remove not-null="true" in mb_comment file ,system is good.But comment_user_id column is null.How to solve?
You should assign the property Person on your Comment to a valid A_Person instance. Then NHibernate will know which user id to write in the table.
I have at my SQL Server 2000 Database a column with type Image. How can I map it into NHibernate?
We used BinaryBlob on the mapping config file, and byte[] on the property.
Below is the sample code that i have used to map an image field. Where BlogImage was a column of Image Datatype mapped to byte type property BlogImage. length="2147483647" was used to ensure copy of full image in to database as nhibernate some times limit the max size of data that is going to be inserted.
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
<class name="EAS.MINDSPACE.Infrastructure.Business.Entities.BlogMaster,EAS.MINDSPACE.Infrastructure.Business.Entities" lazy="false" table="BlogMaster" schema="dbo" >
<id name="BlogId" column="BlogId">
<generator class="native" />
</id>
<property name="BlogData" column="BlogData" />
<property name="BlogImage" column="BlogImage" length="2147483647" />
<property name="UserId" column="UserId" />
<property name="CreatedByName" column="CreatedBy" />
<property name="CreatedOn" column="CreatedOn" />
<property name="ReplyCount" column="ReplyCount" />
</class>
</hibernate-mapping>
NHibernate 3.x does all the magic it self.
Sql:
Create table tblCompany (..., Logo image);
NHibernate-Mapping (important to set length!!!):
<class name="Company"
table="tblCompany">
...
<property name="_logo"
column="Logo"
not-null="false"
length="2147483647"
access="field" />
...
</class>
C#-Class:
public class Company {
...
private Image _logo;
...
}
I'm not sure how to ask the question, for I don't know what I don't know, and therefore I don't know the proper terminology for what I'm trying to get the answer to. I will explain my scenario, in hopes that it will help:
I've got three tables, a Book table, a Tag table and a BookTag lookup table.
Each book has an ID, a Title (for starters)
Each tag has an ID, and a Title
Each BookTag has an ID, a BookID, and a TagID.
A book can be tagged with multiple tags, and a tag can be used on more than one BookID.
I've got my objects setup in this fashion:
Book.cs
int BookID
string Title
List<BookTag> Tags
Tag.cs
int TagID
string Title
BookTag.cs
int ID
int BookID
int TagID
I would like the Books.cs class to have a collection of Tags, and not BookTags, but I cannot seem to get the mapping right in NHibernate. This is what I've got for the Book.hbm.xml file:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DomainModel" namespace="DomainModel.Books">
<class name="DomainModel.Books.Book" table="Books">
<id name="BookID" type="Int32" unsaved-value="0">
<generator class="native"/>
</id>
<property name="Title" type="String" not-null="true"/>
<set lazy="true" name="Tags" table="BookTags" generic="true" inverse="true" cascade="delete">
<key column="BookID"/>
<one-to-many class="DomainModel.Books.BookTag, DomainModel"/>
</set>
</class>
</hibernate-mapping>
And this is my BookTag.hbm.xml:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DomainModel" namespace="DomainModel.Books">
<class name="DomainModel.Books.BookTag" table="BookTags">
<id column="BookTagID" name="BookTagID" type="Int32" unsaved-value="0">
<generator class="native"/>
</id>
<many-to-one name="Tag">
<column not-null="true" name="TagID"/>
</many-to-one>
<many-to-one name="Book">
<column not-null="true" name="BookID"/>
</many-to-one>
</class>
</hibernate-mapping>
Under this model, I can get to the tag I want by using my object model: Book.Tags[0].Tag, but that just seems inefficient. Can I use NHibernate to map out the BookTags.TagID with the Tags.TagID in the database so that I can get Book.Tags[0] to return a Tag object, instead of a BookTags object? I didn't know of a better way to associate Books to tags so that a tag used on Book1 can be used on Book2 without adding a new entry to the Tags table.
I hope this makes at least some sense. Let me know if you need further clarification. I'll post my solution here if I figure it out before someone answers.
You don't need a BookTag class at all. You can map Book.Tags collection as many-to-many. To do this you will specify BookTag in the map to connect the association. Look here in section 6.8 Bidirectional Associations.
Thank you Tim, that was what I needed. For those that are curious, I "un-mapped" the BookTag table/objects, and now just have a Book object and a Tag object that are used and mapped to NHibernate.
My Book.hbm.xml was updated to this:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DomainModel" namespace="DomainModel.Books">
<class name="DomainModel.Books.Book" table="Books">
<id name="BookID" type="Int32" unsaved-value="0">
<generator class="native"/>
</id>
<property name="Title" type="String" not-null="true"/>
<bag name="Tags" table="BookTag" generic="true">
<key column="BookID" on-delete="noaction"></key>
<many-to-many class="Tag" column="TagID"></many-to-many>
</bag>
</class>
</hibernate-mapping>