row1
row1

Reputation: 5578

HasMany Not Null Foreign Key

I have two classes (simplified for the example):

public class Data
{
    public int Id {get; set;}
    public string Value { get; set; }
}
public class DataContainer
{
    public int Id {get; set;}
    public IList<Data> DataPoints { get; set; }
}

Basically the DataContainer class has a collection of Data (and other properties not shown). The Data class does not know about DataContainer but it cannot exist outside of one. I use a HasMany relationship for this.

I map DataContainer like this:

Id(x => x.Id);
HasMany<Data>(x => x.DataPoints)
    .Not.KeyNullable()
    .Cascade.All();

And the generated SQL for Data looks like this:

create table [Data] (
   [Id] INT IDENTITY NOT NULL,
   [DataContainer] INT null,
   primary key ([Id])
)
alter table [Data] 
    add constraint FK173EC9226585807B 
    foreign key ([DataContainer]) 
    references [DataContainer]

The problem is that I don't want [DataContainer] INT null, instead I want it not allow nulls

[DataContainer] INT not null

I thought .Not.KeyNullable() would do this but it doesn't seem to work.

Thanks.

Upvotes: 3

Views: 2505

Answers (2)

Val M
Val M

Reputation: 929

I have the same mapping and have resolved it by making the relationship bidirectional (as suggested by Yhrn) and then enforced the foreign key constraint by adding the Constrained().ForeignKey() declaration to the mapping:

In the Data class:

 this.HasOne(x => x.DataContainer).Cascade.All().Constrained().ForeignKey();

The column in the generated SQL is still nullable but the foreign key has been added:

ALTER TABLE [dbo].[Data]  WITH CHECK ADD  CONSTRAINT [FK_DataToDataContainer] FOREIGN KEY([Id])
REFERENCES [dbo].[DataContainer] ([Id])
GO

ALTER TABLE [dbo].[Data] CHECK CONSTRAINT [FK_DataToDataContainer]
GO

Upvotes: 0

Yhrn
Yhrn

Reputation: 1063

I have the exact same mapping and the same result but looking at the hbm.xml generated by Fluent it looks like it does what it can here. The collection mapping looks something like this (note the "not-null" attribute on the "key" element):

<bag cascade="all" name="Items" mutable="true">
  <key foreign-key="FK_MyEntity2_MyEntity1" not-null="true">
    <column name="MyEntity1_Id" />
  </key>
  <one-to-many class="MyNs.MyEntity2, MyAssembly, Version=0.4.700.0, Culture=neutral, PublicKeyToken=null" />
</bag>

Therefore I think this is a NHibernate issue rather than a Fluent issue. The following is taken from chapter 6.4 in the latest NHibernate reference (3.0.0 but I'm pretty sure the same is true for 2.1.2)

Very Important Note: If the <key> column of a 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.

So my guess is that NHibernate simply ignores the "not-null" attribute when generating the DDL for this mapping and that the solution is to make the association bidirectional as suggested above (definitely works but may not suit your scenario) or live with a NULL column.

Upvotes: 2

Related Questions