Nhibernate not save foreign key id

I have a simple model that I am trying to use with fluent-nhibernate:

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public IList<Address> Addresses { get; set; }
}

public class Address
{
    public int Id { get; set; }
    public int PersonId { get; set; }
    public string Street { get; set; }        
}

Some sample data:

var person = new Person() {Name = "Name1", Addresses = new[]
    {
        new Address { Street = "Street1"},
        new Address { Street = "Street2"}
    }};

When I call session.SaveOrUpdate(person), both objects are saved, but the foreign key is not saved in the Address table:

enter image description here

What am I doing wrong? My mapping overrides are as follows:

public class PersonOverrides : IAutoMappingOverride<Person>
{
    public void Override(AutoMapping<Person> mapping)
    {
        mapping.Id(x => x.Id);
        mapping.HasMany(x => x.Addresses).KeyColumn("PersonId").Cascade.All();            
    }
}

public class AddressOverrides : IAutoMappingOverride<Address>
{
    public void Override(AutoMapping<Address> mapping)
    {
        mapping.Id(x => x.Id);               
    }
}

Please note: I plan to use List<Address>in other objects, and I do not want to add a property Address.Person.

UPDATE 1

, "", Address.PersonId Address.Person, , Address Person, . , , , nHibernate 1) 2) NULL PersonId 3) PersonId ( ) 2 3 ? , NULL Address.PersonId

2 Address.PersonId PersonId . nHibernate , PersonId, / . Address.PersonId ", , , , , ". , , nHibernate, , NULL PersonId ( Save ing), THEN ( Flush ing)??

+5
5

, , .

BEGIN; SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
select nextval ('person_person_id_seq')
select nextval ('person_person_id_seq')
select nextval ('phone_number_phone_number_id_seq')
select nextval ('phone_number_phone_number_id_seq')
select nextval ('phone_number_phone_number_id_seq')
select nextval ('phone_number_phone_number_id_seq')
INSERT INTO person (lastname, firstname, person_id) VALUES (((E'McCartney')::text), ((E'Paul')::text), ((109)::int4))
INSERT INTO person (lastname, firstname, person_id) VALUES (((E'Lennon')::text), ((E'John')::text), ((110)::int4))
INSERT INTO phone_number (the_phone_number, person_id, phone_number_id) VALUES (((E'9')::text), ((NULL)::int4), ((306)::int4))
INSERT INTO phone_number (the_phone_number, person_id, phone_number_id) VALUES (((E'8')::text), ((NULL)::int4), ((307)::int4))
INSERT INTO phone_number (the_phone_number, person_id, phone_number_id) VALUES (((E'6')::text), ((NULL)::int4), ((308)::int4))
INSERT INTO phone_number (the_phone_number, person_id, phone_number_id) VALUES (((E'1')::text), ((109)::int4), ((309)::int4))
UPDATE phone_number SET person_id = ((110)::int4) WHERE phone_number_id = ((306)::int4)
UPDATE phone_number SET person_id = ((110)::int4) WHERE phone_number_id = ((307)::int4)
UPDATE phone_number SET person_id = ((110)::int4) WHERE phone_number_id = ((308)::int4)
UPDATE phone_number SET person_id = ((110)::int4) WHERE phone_number_id = ((309)::int4)
COMMIT

...

public class PersonMap : ClassMap<Person>
{
    public PersonMap ()
    {           
        Id (x => x.PersonId).GeneratedBy.Sequence("person_person_id_seq");

        Map (x => x.Lastname).Not.Nullable();
        Map (x => x.Firstname).Not.Nullable();

        // No Inverse
        HasMany(x => x.PhoneNumbers).Cascade.All ();
    }
}

public class PhoneNumberMap : ClassMap<PhoneNumber>     
{
    public PhoneNumberMap ()
    {
        References(x => x.Person);          

        Id (x => x.PhoneNumberId).GeneratedBy.Sequence("phone_number_phone_number_id_seq");

        Map (x => x.ThePhoneNumber).Not.Nullable();                       
    }
}

... .

(), , , -, ...

public static void Main (string[] args)
{
    var sess = Mapper.GetSessionFactory().OpenSession();

    var tx = sess.BeginTransaction();

    var jl = new Person { Firstname = "John", Lastname = "Lennon", PhoneNumbers = new List<PhoneNumber>() };
    var pm = new Person { Firstname = "Paul", Lastname = "McCartney", PhoneNumbers = new List<PhoneNumber>() };

    // Notice that we didn't indicate Parent key(e.g. Person = jl) for ThePhoneNumber 9.       
    // If we don't have Inverse, it up to the parent entity to own the child entities
    jl.PhoneNumbers.Add(new PhoneNumber { ThePhoneNumber = "9" });
    jl.PhoneNumbers.Add(new PhoneNumber { ThePhoneNumber = "8" });
    jl.PhoneNumbers.Add(new PhoneNumber { ThePhoneNumber = "6" });

    jl.PhoneNumbers.Add(new PhoneNumber { Person = pm, ThePhoneNumber = "1" });


    sess.Save (pm);
    sess.Save (jl);                     


    tx.Commit();            
}

..., , - ; , , , NULL , . , ThePhoneNumber "1" , PhoneNumber, John John; , , , , . : -)

SQL ,


Inverse

, , , ; .

Main, ...

HasMany(x => x.PhoneNumbers).Inverse().Cascade.All ();

... , ThePhoneNumber "1", ( ), , - . , , . Inverse , , .

-, :

BEGIN; SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
select nextval ('person_person_id_seq')
select nextval ('person_person_id_seq')
select nextval ('phone_number_phone_number_id_seq')
select nextval ('phone_number_phone_number_id_seq')
select nextval ('phone_number_phone_number_id_seq')
select nextval ('phone_number_phone_number_id_seq')
INSERT INTO person (lastname, firstname, person_id) VALUES (((E'McCartney')::text), ((E'Paul')::text), ((111)::int4))
INSERT INTO person (lastname, firstname, person_id) VALUES (((E'Lennon')::text), ((E'John')::text), ((112)::int4))
INSERT INTO phone_number (the_phone_number, person_id, phone_number_id) VALUES (((E'9')::text), ((NULL)::int4), ((310)::int4))
INSERT INTO phone_number (the_phone_number, person_id, phone_number_id) VALUES (((E'8')::text), ((NULL)::int4), ((311)::int4))
INSERT INTO phone_number (the_phone_number, person_id, phone_number_id) VALUES (((E'6')::text), ((NULL)::int4), ((312)::int4))
INSERT INTO phone_number (the_phone_number, person_id, phone_number_id) VALUES (((E'1')::text), ((111)::int4), ((313)::int4))
COMMIT

, ?

-, , Hibernate/NHibernate, . , , . .

-, , , . , .

public class Person
{
    public virtual int PersonId { get; set; }
    public virtual string Lastname { get; set; }
    public virtual string Firstname { get; set; }

    public virtual IList<PhoneNumber> PhoneNumbers { get; set; }


    public virtual void AddToPhoneNumbers(PhoneNumber pn)
    {
        pn.Person = this;
        PhoneNumbers.Add(pn);
    }
}

:

public static void Main (string[] args)
{
    var sess = Mapper.GetSessionFactory().OpenSession();

    var tx = sess.BeginTransaction();

    var jl = new Person { Firstname = "John", Lastname = "Lennon", PhoneNumbers = new List<PhoneNumber>() };
    var pm = new Person { Firstname = "Paul", Lastname = "McCartney", PhoneNumbers = new List<PhoneNumber>() };

    jl.AddToPhoneNumbers(new PhoneNumber { ThePhoneNumber = "9" });
    jl.AddToPhoneNumbers(new PhoneNumber { ThePhoneNumber = "8" });
    jl.AddToPhoneNumbers(new PhoneNumber { ThePhoneNumber = "6" });

    pm.AddToPhoneNumbers(new PhoneNumber { ThePhoneNumber = "1" });


    sess.Save (pm);
    sess.Save (jl);                     


    tx.Commit();            
}

:

BEGIN; SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
select nextval ('person_person_id_seq')
select nextval ('phone_number_phone_number_id_seq')
select nextval ('person_person_id_seq')
select nextval ('phone_number_phone_number_id_seq')
select nextval ('phone_number_phone_number_id_seq')
select nextval ('phone_number_phone_number_id_seq')
INSERT INTO person (lastname, firstname, person_id) VALUES (((E'McCartney')::text), ((E'Paul')::text), ((113)::int4))
INSERT INTO phone_number (the_phone_number, person_id, phone_number_id) VALUES (((E'1')::text), ((113)::int4), ((314)::int4))
INSERT INTO person (lastname, firstname, person_id) VALUES (((E'Lennon')::text), ((E'John')::text), ((114)::int4))
INSERT INTO phone_number (the_phone_number, person_id, phone_number_id) VALUES (((E'9')::text), ((114)::int4), ((315)::int4))
INSERT INTO phone_number (the_phone_number, person_id, phone_number_id) VALUES (((E'8')::text), ((114)::int4), ((316)::int4))
INSERT INTO phone_number (the_phone_number, person_id, phone_number_id) VALUES (((E'6')::text), ((114)::int4), ((317)::int4))
COMMIT

: fooobar.com/questions/67986/...

+10

, ,

public class Person
    {
        public virtual int Id { get; set; }

        public virtual string Name { get; set; }

        public virtual IList<Address> Addresses { get; set; }

    }

public class Address
    {
        public virtual int Id { get; set; }

        public virtual int PersonId { get; set; }

        public virtual string Street { get; set; }  
    }

public class PersonOverrides : IAutoMappingOverride<Person>
    {
        public void Override(AutoMapping<Person> mapping)
        {
            mapping.Id(x => x.Id);
            mapping.HasMany(x => x.Addresses).KeyColumn("PersonId").Cascade.All();            
        }
    }

,

public class AddressOverrides : IAutoMappingOverride<Address>
    {
        public void Override(AutoMapping<Address> mapping)
        {
            mapping.Id(x => x.Id);
            mapping.Map(x => x.PersonId).Column("PersonId");
        }
    }
+1

PersonId , . :

  • PersonId Person Person
  • , ( nhibernate )
  • XML , nhiberante .
0

. IAutoMappingOverride, , AnswerMap :

public class QuestionMap : ClassMap<Question>
{
    public QuestionMap()
    {
        Id(x => x.QuestionId).GeneratedBy.Sequence("question_seq");

        Map(x => x.TheQuestion).Not.Nullable();

        HasMany(x => x.Answers).Inverse().Not.LazyLoad().Cascade.AllDeleteOrphan();
    }
}

public class AnswerMap : ClassMap<Answer>
{
    public AnswerMap()
    {
        References(x => x.Question);

        Id(x => x.AnswerId).GeneratedBy.Sequence("answer_seq");

        Map(x => x.TheAnswer).Not.Nullable();
    }
}

</" > :

public class Question
{
    public virtual int QuestionId { get; set; }

    public virtual string TheQuestion { get; set; }        

    public virtual IList<Answer> Answers { get; set; }
}

public class Answer
{
    public virtual Question Question { get; set; }

    public virtual int AnswerId { get; set; }

    public virtual string TheAnswer { get; set; }                
}

, public virtual int QuestionId { get; set; } on Answer, public virtual Question Question { get; set; }. , , , , , ( int, .., )

, ( session.Load) .

var answer = new Answer {
   // session.Load does not make database request
   Question = session.Load<Question>(primaryKeyValueHere), 

   TheAnswer = "42"
};
0

,

,

""

.

Address {AddressId, ...}
PersonAddress : Address {Person, ...}, 
CustomerAddress : Address {Customer, ...}, 
VendorAddress : Address {Vendor, ...}

,

:

db, /

Persons [PersonId, ...]
Addresses [AddressId]
AddressDetails [AddressDetailId, AddressId, ...]

( , , xml) 1.) + 2.) +

...

0
source

All Articles