开发者

Fluent Nhibernate mapping multiple classes to single foreign key

开发者 https://www.devze.com 2023-01-24 05:30 出处:网络
I have a database structure where one table extends another table开发者_StackOverflow中文版, and then a third table has a foreign key that is valid in the first two tables.

I have a database structure where one table extends another table开发者_StackOverflow中文版, and then a third table has a foreign key that is valid in the first two tables.

For example:

TABLE Person
PersonId int
Name varchar
ShirtId int

TABLE Shirt
ShirtId int
Color string

TABLE SpecialShirt
ShirtId int
Sleeves int

The classes look like this:

public class Person
{
    public virtual int PersonId { get; set; }
    public virtual string Name { get; set; }
    public virtual Shirt Shirt { get; set; }
    public virtual SpecialShirt SpecialShirt { get; set; }
}

public class Shirt
{
    public Shirt()
    {
        PersonList = new List<Person>();
    }

    public virtual int ShirtId { get; set; }
    public virtual string Color { get; set; }
    public virtual IList<Person> PersonList { get; set; }
    public virtual void AddPerson(Person p)
    {
        PersonList.Add(p);
    }
}

public class SpecialShirt : Shirt
{
    public virtual int Sleeves { get; set; }
}

And the mappings look like this:

public class TestPersonMap : ClassMap<TestPerson>
{
    public TestPersonMap()
    {
        Table("TestPerson");
        Id(x => x.PersonId).GeneratedBy.Native();
        Map(x => x.Name);
        References(x => x.Shirt).Column("ShirtId");
        References(x => x.SpecialShirt).Column("ShirtId"); // commenting out this line works
    }
}

public class TestShirtMap : ClassMap<TestShirt>
{
    public TestShirtMap()
    {
        Table("TestShirt");
        Id(x => x.ShirtId).GeneratedBy.Native();
        Map(x => x.Color);
        HasMany(x => x.PersonList).KeyColumn("ShirtId").Inverse().Cascade.All();
    }
}

public class TestSpecialShirtMap : SubclassMap<TestSpecialShirt>
{
    public TestSpecialShirtMap()
    {
        Table("TestSpecialShirt");
        KeyColumn("ShirtId");
        Map(x => x.Sleeves).Column("Sleeves");
    }
}

I then try saving a new instance of Person and Shirt like this:

var shirt1 = new TestShirt() {Color = "Red"};
var person1 = new TestPerson() {Name = "Fred Person", Shirt = shirt1};
shirt1.AddPerson(person1);

session.Save(shirt1);
session.Save(person1);

This code gets the following error:

System.ArgumentOutOfRangeException : Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index

It works if I remove the reference from Person to SpecialShirt. Howe can I have two references on the same column ("ShirtId")? Or is there a better way? I can't really change the table structure.


How does the relationship work? Usually, a Person wears a Shirt, and a Shirt is either a Shirt or a SpecialShirt. Because a SpecialShirt is a Shirt, a Person need only have a reference to a Shirt. NHibernate knows all about table-per-concrete-class mappings (which is what you have).


I found a solution. It's ugly, but it's working. I added the command DynamicInsert() into the PersonMap. So the map is now:

public class TestPersonMap : ClassMap<TestPerson>
{
 public TestPersonMap()
 {
  Table("TestPerson");
  Id(x => x.PersonId).GeneratedBy.Native();
  Map(x => x.Name);
  References(x => x.Shirt).Column("ShirtId");
  References(x => x.SpecialShirt).Column("ShirtId"); 

  DynamicInsert();
 }
}

I then have to save the Shirt and Person separately, so the cascade is not really working.

This is working so far. I honestly don't know what DynamicInsert does. I can only find out-of-date documentation and unhelpful forum threads when researching this method.

I can only assume this will be fail at some point in the future.

0

精彩评论

暂无评论...
验证码 换一张
取 消