Implementing unidirectional associations results in optional foreign key fields via NHibernate

Updated Added mappings below

Summary of the question I have a database with many mandatory foreign key fields and a code base with many one-way associations. I want to use NHibernate, but as far as I can tell, I need to either introduce foreign key fields in the database to NULLable (not a realistic option) or change the associations to bi-directional (not ideal). Any other options I missed?

Background I joined a project that uses NHibernate to map tables 1: 1 to so called "technical" entities. After the data has been retrieved, the objects are mapped to the actual domain model (AutoMapper style implemented in different ways). I know this is an extra step and I want to suggest removing it to the command. However, I ran into a problem.

The domain model contains many unidirectional associations: the Case object has a list of persons associated with this case, but the Persons do not have a reference to the Case object. In the underlying database schema, the Person table has a required foreign key field that references the case identifier. Data model:

[ERD]
               PERSON
CASE           Id*            Ids are generated by the DB
Id*    <--FK-- CaseId*        * denotes required fields
(other)        (other)         

      

The domain model looks like this:

public class Person : DomainEntity
{ // DomainEntity implements Id. Non-essential members left out }

public class Case : DomainEntity
{
  public virtual IList<Person> Persons { get; set; }
}

      

Calling session.Save () in case results in a database error (CaseId is required when inserting into Person), because NHibernate starts by inserting Person records and then with a Case record and ends up updating the CaseId column in Person records. If the CaseId column in the database is changed to optional (allow NULL), everything works as it should ... however, this change is not an option at the moment (the database model is shared across multiple applications, at least for another year). The only way NHibernate can find to do the right thing with the database is to change the association to bidirectional i.e. By changing Person to

public class Person : DomainEntity
{ 
  public virtual Case Case { get; set; }
}

      

This will require significant changes to the existing codebase, so I would prefer alternatives if they exist. I've played with component mappings, but it doesn't fit well since most of the associations in our model are not actual (UML) compositions. Are there any other options I missed? TIA!

EDIT Mapping (Fluent) for Case looks like this:

public class CaseMapping : ClassMap<Case>
{
    public CaseMapping()
    {
        Not.LazyLoad();

        Id(c => c.Id).GeneratedBy.Identity();
        Map(x => x.Code).Not.Nullable().Length(20);
        Map(x => x.Name).Not.Nullable().Length(100);
        HasMany<Person>(x => x.Persons)
            .AsBag()
            .KeyColumn("CaseId")
            .ForeignKeyConstraintName("FK_Person_Case")
            .Cascade.AllDeleteOrphan();
    }
}

      

If I use SessionSource.BuildSchema on a test database, this creates a Person table with a null CaseId column. I haven't found a way for this to work with an invalid CaseId field without bi-directional associations. Executed (pseudo) SQL statements:

  • INSERT INTO Case

    ...
  • select @@ identity
  • INSERT INTO Person

    / * (all columns except CaseId) * /
  • select @@ identity
  • UPDATE Person

    SET CaseId =? WHERE Id = ?; @ P0 = 2, @ p1 = 1
+2


source to share


1 answer


I guess you're out of luck here. Docs at http://nhibernate.info/doc/nh/en/index.html#collections-onetomany state:



If an association column is declared NOT NULL, NHibernate can cause constraint violations when creating or updating the association. To prevent this problem, you must use a bi-directional link with a multi-valued end (set or bag) indicated by inverse = "true"

+1


source







All Articles