views:

1530

answers:

3

I have a Master Detail relationship configured. The hbm file is below. When I run some code like this

Favourite favourite = favourites.Find(f => f.Id== id);
user.Favourites.Remove(favourite);
m_UserRepository.Save(ref user);

I get the error message

NHibernate.Exceptions.GenericADOException: could not delete collection rows: [Model.Entities.User.Favourites#249][SQL: SQL not available] ---> System.Data.SqlClient.SqlException: Cannot insert the value NULL into column 'UserId', table 'BE.Favourite'; column does not allow nulls. UPDATE fails.

Any suggestions on what this means please help.

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Model.Entities" schema="BE" assembly="Model" default-lazy="false">
  <class name="Model.Entities.User, Model" table="Users" >
    <id name="UserId" column="UserId" type="int" unsaved-value="0">
      <generator class="native" />
    </id>
    <property name="UserName" column="UserName" type="string" />

    <bag name="Favourites" cascade="all" lazy="true">
      <key column="UserId"/>
      <one-to-many class="Model.Entities.Favourite, Model"/>
    </bag>

  </class>
</hibernate-mapping>
A: 

try changing your cascade rule to:

<bag name="Favourites" cascade="all,delete-orphan" lazy="true">
  <key column="UserId" not-null="true"/>
  <one-to-many class="Model.Entities.Favourite, Model"/>
</bag>
Elie
Thanks, but I still get the same error.
Craig
Sorry, try this. Forgot the not-null tag.
Elie
I get an error about not-null not being a valid attribute.
Craig
+1  A: 

Have you tried setting inverse="true" on your bag?

James Gregory
Setting inverse="true" would make it so that he would have to delete the details manually after deleting the master. I don't know if that is what he's going for here.
Min
+3  A: 

You actually need a many-to-many relationship in this case:

<class name="User">
  <id name="Id">
    <generator class="native">
      <param name="sequence">object_sequence</param>
    </generator>
  </id>
  <version name="Version" />
  <property name="Name" />
  <set name="Roles" table="User_Favourite">
    <key column="UserId"/>
    <many-to-many column="FavouriteId" class="Favourite"/>
  </set>
</class>

And the same on the other side: (*note the inverse="true")

<class name="Favourite">
  <id name="Id">
    <generator class="native">
      <param name="sequence">object_sequence</param>
    </generator>
  </id>
  <version name="Version" />
  <property name="RoleName" />
  <set name="Users" table="User_Favourite" inverse="true">
    <key column="FavouriteId"/>
    <many-to-many column="UserId" class="User"/>
  </set>
</class>

From the NHibernate 2.0 Documentation:

Very Important Note: If the <key> column of a <one-to-many> association is declared NOT NULL, NHibernate may cause constraint violations when it creates or updates the association. To prevent this problem, you must use a bidirectional association with the many valued end (the set or bag) marked as inverse="true". See the discussion of bidirectional associations later in this chapter.

Finally, I'm unsure if you really want to use a bag here. One user can have the same favorite two or more times?

P.S.: Also, note that lazy="true" is the default behavior since NHibernate 1.2.

F.D.Castel