2

I have the following tables:

  • LANDLORD = Id (Primary Key), FirstName, Surname, EmailAddress, Title;
  • PROPERTY = Id (Primary Key), Type, NumberOfBedrooms, Address1, Address2, City, County, PostCode, LandlordId (Foreign Key to Landlord entity);

My Domain classes are:

public class Landlord:BaseEntity
{
    public virtual string Title { get; set; }
    public virtual string Surname { get; set; }
    public virtual string FirstName { get; set; }
    public virtual string EmailAddress { get; set; }
    public virtual IList<Property> Properties { get; set; }

    public Landlord()
    {
        Properties = new List<Property>();
    }
}

public class Property:BaseEntity
{
    public virtual string Type { get; set; }
    public virtual int NumberOfBedrooms { get; set;}
    public virtual string Address1 { get; set; }
    public virtual string Address2 { get; set; }
    public virtual string City { get; set; }
    public virtual string County { get; set; }
    public virtual string PostCode { get; set; }
    public virtual Landlord Landlord { get; set; }

}

My Fluent NHibernate maps are:

public sealed class LandlordMap:ClassMap<Landlord>
{
    public LandlordMap()
    {
        Id(x => x.Id).GeneratedBy.Identity();
        Map(x => x.Title);
        Map(x => x.Surname);
        Map(x => x.FirstName);
        Map(x => x.EmailAddress);
        HasMany(x => x.Properties)
            .KeyColumns.Add("LandlordId")
            .Inverse()
            .Cascade.All();
        Table("LANDLORD");
    }
}

public sealed class PropertyMap:ClassMap<Property>
{
    public PropertyMap()
    {
        Id(x => x.Id).GeneratedBy.Identity(); 
        Map(x => x.Type);
        Map(x => x.NumberOfBedrooms);
        Map(x => x.Address1);
        Map(x => x.Address2);
        Map(x => x.City);
        Map(x => x.County);
        Map(x => x.PostCode);
        References(x => x.Landlord, "LandlordId");
        Table("PROPERTY");
    }
}

To test that a Landlord is saved to the database, I have the following code:

public class Program
{
    static void Main(string[] args)
    {
        ILandlordRepository rep = new LandlordRepository();

        //Create property object
        Property p1 = new Property
        {
            Address1 = "123 LA Road",
            Address2 = "Bilston",
            City = "Harlem",
            County = "West Mids",
            NumberOfBedrooms = 2,
            PostCode = "wv134wd",
            Type = "Bungalow"
        };

        //Create landlord and assign property
        var landlord = new Landlord();
        landlord.Title = "Dr";
        landlord.FirstName = "Rohit";
        landlord.Surname = "Kumar";
        landlord.EmailAddress = "rkhkp@p.com";
        landlord.Properties.Add(p1);

        //Add to the database
        rep.SaveOrUpdate(landlord);


        Console.ReadKey();

    }
}

When I call SaveOrUpdate I get this error:

could not insert: [Homes4U.Service.DomainClasses.Property][SQL: INSERT INTO PROPERTY (Type, NumberOfBedrooms, Address1, Address2, City, County, PostCode, LandlordId) VALUES (?, ?, ?, ?, ?, ?, ?, ?); select SCOPE_IDENTITY()]

Does anybody now why this is happening?

Himanshu
  • 31,810
  • 31
  • 111
  • 133

1 Answers1

0

In your mappings, you've specified that the Property object is responsible for saving its reference to Landlord.

HasMany(x => x.Properties)
            .KeyColumns.Add("LandlordId")
             // Inverse means that the other side of the 
             // relationship is responsible for creating the reference
            .Inverse()
            .Cascade.All();

When you attempt to save the object, the Property object in the Properties collection has no reference to the landlord it belongs to. Under the hood, it'll attempt to insert a NULL into the LandlordId column.

This is why you are getting your error.

EDIT

To resolve, save the landlord first, without a reference to any property.

    ILandlordRepository rep = new LandlordRepository();
    IPropertyRepository pro = new PropertyRepository();

    //Create landlord
    var landlord = new Landlord();
    landlord.Title = "Dr";
    landlord.FirstName = "Rohit";
    landlord.Surname = "Kumar";
    landlord.EmailAddress = "rkhkp@p.com";

    rep.SaveOrUpdate(landlord);

    // Now add the landlord reference to the property and
    // save
    /Create property object
    Property p1 = new Property
    {
        Address1 = "123 LA Road",
        Address2 = "Bilston",
        City = "Harlem",
        County = "West Mids",
        NumberOfBedrooms = 2,
        PostCode = "wv134wd",
        Type = "Bungalow",
        Landlord = landlord
    };

    pro.SaveOrUpdate(p1);

You may need to reload the Landlord after saving it.

EDIT 2

See this question on Inverse.

Inverse Attribute in NHibernate

Community
  • 1
  • 1
Paul Alan Taylor
  • 10,474
  • 1
  • 26
  • 42
  • Sorry, im a bit of a newbie to NHibernate, but isn't the point of NHiberate to save the parent and it will take care of saving the child element in this case property? – user1737371 Oct 11 '12 at 09:55
  • If that's the behaviour you seek, you'll need to reverse the relationship ( take out the inverse ). – Paul Alan Taylor Oct 11 '12 at 10:02