These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 posts ] 
Author Message
 Post subject: Automagically enforce unique constraint
PostPosted: Tue Jul 11, 2006 2:26 am 
Newbie

Joined: Sun Jun 25, 2006 9:17 pm
Posts: 7
Location: Tempe, Az
Is it possible to get NHibernate to enforce a unique constraint for me by attempting to load the existing reference to the key instead of just inserting it? Say I have the following classes:
Code:
public class item
{
       //....declarations
        public CASNum CASNumber{//get\set stuff here}
}

public class cas_num
{
      public string CAS{//get\set}

      public long cas_id{//get\set}
}


In the database, there are two tables: items and cas_nums. items has a foreign key to cas_id (which is cas_nums' primary key). In addition, the field CAS has a unique constraint. CAS would be a candidate key if I wasn't using surrogate keys.

When I save an item, I would like NHibernate to look up whether that CAS already exists and if so, use that CAS's cas_id in the foreign key in the items table for that item.

Presently, NHibernate blindly attempts to insert the CAS, so if it's a duplicate, I get a duplicate key constraint violation.

Should I just implement this in my business code, or can NHibernate look the key up for me as detailed above?


Hibernate version: 1.02

Mapping documents:
casNum.hbm.xml
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0" assembly="data" namespace="data">
   <class name="CASNum" table="cas_nums">
      <id name="ID" column="cas_id" type="Int64" unsaved-value="-1">
         <generator class="sequence">
            <param name="sequence">cas_num_id_seq</param>
         </generator>
      </id>
      <property name="CAS" column="cas_num" type="String" unique="true" />
      
      <property name="Compound" column="chemical" type="String" />
   </class>
</hibernate-mapping>

item.hbm.xml
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0" assembly="data" namespace="data">
   <class name="Item" table="current_inventory">
      <id name="ID" column="item_id" type="Int64" unsaved-value="-1">
         <generator class="sequence">
            <param name="sequence">item_id_seq</param>
         </generator>
      </id>
      <many-to-one name="CASNum" class="CASNum" column="cas_id" />
   </class>
</hibernate-mapping>

Name and version of the database you are using: PostgreSQL 8.1

The generated SQL (show_sql=true):
Code:
NHibernate: select nextval ('cas_num_id_seq')
NHibernate: INSERT INTO cas_nums (chemical, cas_num, cas_id) VALUES (:p0, :p1, :p2)
:p0 = ''
:p1 = '58-08-2'
:p2 = '515'


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 11, 2006 4:14 am 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
Implement it in the business code, NHibernate doesn't offer this functionality.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 11, 2006 11:42 am 
Newbie

Joined: Sun Jun 25, 2006 9:17 pm
Posts: 7
Location: Tempe, Az
Ahh, okay. For some reason I assumed it would.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 11, 2006 12:29 pm 
Newbie

Joined: Tue Jul 11, 2006 12:13 pm
Posts: 1
I have a follow up question for this post. For some time now, I've had a nagging problem with the architecture that I'm using.

Just to quickly explain my architecture, I'm using a Domain Model exposed to the world via a Service Layer that persists and retrieves the Domain Objects via a Data Access Layer built on NHibernate. Since Domain Objects are used to transfer data between layers, all of the other layers depend on the Domain Model while the Domain Model depends on nothing. This is a pretty standard architecture that I assume most NHibernate users apply in one form or another.

My problem is this, if the Domain Model (which contains the business logic) is supposed to perform validation such as checking for duplicates, does the Domain Model not then have to rely on the Data Access Layer? How else it retrieve the potential duplicate objects? While in theory this may not be a problem, I've just created a circular reference between layers which pretty much all programming languages will not allow.

How have other people out there solved this problem? Any suggestions would be much appreciated.

Thanks,
Matt


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 13, 2006 7:12 am 
Regular
Regular

Joined: Mon Jul 18, 2005 4:10 am
Posts: 92
Location: Poland
Personally I prefer separating Bussiness Layer and domain objects , so it can depend on data access layer (NHibernate in my case). Then I can do the validation in the Bussiness Layer.

_________________
michal


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 13, 2006 8:23 am 
Newbie

Joined: Mon Jun 26, 2006 12:27 pm
Posts: 16
Well, I don't know if this makes sense, but what I did was create a business layer that consisted of two parts (you might consider them layers). One were the business domain objects. For example, a Car. Each domain object then has a data access layer, for example a CarDAL object. The get a car, persist a car, etc you called the CarDAL object. It exposes no NHibernate methods, functionality, etc which makes it very generic. Only under the hood to the DAL objects do their work by making calls into a generic DataAccess layer which contains the NHibernate implementation. This allows domain objects to check validations and do other things by simply calling methods on the data access objects.

For example, if a Car's model had to be unique, the CarDAL object could have a method that checked for a particular model. A car object could call this before it is persisted in some sort of validation method. In my case, I make all domain/business objects implement an interface that requires a validation method, this way if the DAL layer is asked to save a domain object it automatically calls the validation method first which will raise a validation exception if something isn't right.

Anyway, hopefully this makes sense. I have domain objects which are pure objects and know nothing about persistance. I then have an object that handles data access for that object that, again, exposes logical methods that consumers of domain objects, or domain objects themselves can access. It exposes nothing at all that is NHibernate specific so the actual data access implementation could be swapped out if necessary. If I understand you correctly, the way I'm using the DAL layer could be used as your service layer. I don't quite see the purpose of a service layer and a DAL layer unless your DAL layer is built NHibernate specific.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 13, 2006 9:11 am 
Regular
Regular

Joined: Mon Jul 18, 2005 4:10 am
Posts: 92
Location: Poland
Ok, I am not very good at this stuff, but I will try to explain the way which works for me:

1. Domain objects are simple "dumb" dataholders, with very simple logic (ie. property fullname = firstname+surname ) .
2. Every object has it's 'logic object' with CRUD metods. The bussiness rules are enforced here.
3. My DAL is NHibernate itself. So 'logic objects' can access it directly.
4. I suppose that my 'logic objects' are acting as your 'service layer'.

Maybe not a nicest application design but works for me.


Going back to your problem, I am not an expert, but maybe "dependency injection" design pattern is the solution you need ? (google for that )

_________________
michal


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.