Fluent NHibernate one-to-many relationship setting

2019-03-29 07:46发布

问题:

I have a simple Fluent NHibernate model with two related classes:

public class Applicant
    {
        public Applicant()
        {
            Tags = new List<Tag>();
        }

        public virtual int Id { get; set; }

        //other fields removed for sake of example

        public virtual IList<Tag> Tags { get; protected set; }

        public virtual void AddTag(Tag tag)
        {
            tag.Applicant = this;
            Tags.Add(tag);
        }
    }


public class Tag
{
    public virtual int Id { get; protected set; }
    public virtual string TagName { get; set; }

    public virtual Applicant Applicant { get; set; }
}

My fluent mapping is the following:

public class ApplicantMap : ClassMap<Applicant>
    {
        public ApplicantMap()
        {
            Id(x => x.Id);

            HasMany(x => x.Tags).Cascade.All();
        }
    }

    public class TagMap : ClassMap<Tag>
    {
        public TagMap()
        {
            Id(x => x.Id);
            Map(x => x.TagName);

            References(x => x.Applicant).Not.Nullable();
        }
    }

Whenever I try to update an applicant (inserting a new one works fine), it fails and I see the following SQL exception in the logs:

11:50:52.695 [6] DEBUG NHibernate.SQL - UPDATE [Tag] SET Applicant_id = null WHERE Applicant_id = @p0;@p0 = 37 [Type: Int32 (0)] 
11:50:52.699 [6] ERROR NHibernate.AdoNet.AbstractBatcher - Could not execute command: UPDATE [Tag] SET Applicant_id = null WHERE Applicant_id = @p0 System.Data.SqlClient.SqlException (0x80131904): Cannot insert the value NULL into column 'Applicant_id', table 'RecruitmentApp.dbo.Tag'; column does not allow nulls. UPDATE fails.

Why is NHibernate trying to update the tag table and set Applicant_id to null? I'm at a loss on this one.

回答1:

Set Applicant.Tags to Inverse will instruct NHibernate to save Tags after the Applicant.

public class ApplicantMap : ClassMap<Applicant>
{
    public ApplicantMap()
    {
        Id(x => x.Id);

        HasMany(x => x.Tags).Cascade.All().Inverse();
    }
}

More detail:

Inverse (as opposed to .Not.Inverse()) means the other side of the relationship (in this case, each Tag) is responsible for maintaining the relationship. Therefore, NHibernate knows that the Applicant must be saved first so that Tag has a valid foreign key for its Applicant.

Rule of thumb: The entity containing the foreign key is usually the owner, so the other table should have Inverse