One to Many mapping with an intermediate table

2019-02-20 08:18发布

问题:

I thought I had this one pegged by mapping the intermediary table as a HasMany and between intermediary and child as HasOne, however HasOne expects to share a key. (No Inverse option.:[ )

Anyhow, the relational structure I have:

Address (Child)
AddressId
..Address Fields

AddressCustomer (Intermediary)
AddressCustomerId
AddressId
CustomerId

Customer (Parent)
CustomerId
..Customer Fields

Why I have this intermediary table instead of a normal 1-many? Because there will be other entities that will need to contain addresses. (I.e. Sites, etc.) They will have their own intermediary table so they can share the address table.

Mappings I have so far:

    public class CustomerAddressMap : ClassMap<CustomerAddress>
{
    public CustomerAddressMap()
    {
        Schema("dbo");
        Table("CustomerAddress");
        Id(x => x.CustomerAddressId);
        Map(x => x.FromDate)
            .Not.Nullable();
        Map(x => x.ToDate);
        HasOne(x => x.Address)
            .ForeignKey("AddressId")
            .Cascade.All();
    }

}

public class AddressMap : ClassMap<Address>
{
    public AddressMap()
    {
        Schema("dbo");
        Table("Address");
        Id(x=>x.AddressId);
        Map(x => x.AddressType);
    }
}

With a null-able AddressId column in the CustomerAddress table, rows are inserted, however the AddressID from the Address row doesn't propagate back up to CustomerAddress. There is no Inverse option on HasOne so that seems to be a dead end. I cannot have the Address ID generated on CustomerAddress because this would result in duplicates once I add something like SiteAddress and have to do the same thing. That trick may work with GUIDs as keys, but I'm stuck with auto-increment Ints for the moment.

Some other ideas I was noodling over was mapping a merge of CustomerAddress and Address but I don't believe that is supported with Fluent NHibby.

I figure it's a problem domain that someone has successfully applied. Essentially I want a 1-Many relationship where the child table (not it's records) is shared between multiple parents. Any ideas?

回答1:

map it as normal references

public class CustomerAddressMap : ClassMap<CustomerAddress>
{
    public CustomerAddressMap()
    {
        Table("CustomerAddress");

        Id(x => x.CustomerAddressId);
        Map(x => x.FromDate).Not.Nullable();
        Map(x => x.ToDate);
        References(x => x.Customer, "CustomerId");
        References(x => x.Address, "AddressId");
    }
}


回答2:

Why won't you make one-to-many from address to customer? Customer will contain foreign key then and address entity could be referened by other entity. In this case, you simply make References(x => x.Address); on customer table.
When I was trying to create one-to-one relation using FluentNHibernate, I faced common problems too. If you want to leave DB structure as you showed, I guess you should try the following mapping (with adding corresponding entity fields):

 public AddressMap()
 {
    Schema("dbo");
    Table("Address");
    Id(x => x.AddressId);
    Map(x => x.AddressType);
    HasOne(x => x.CustomerAddress).Cascade.All();
 }
 public CustomerAddressMap()
 {
     Schema("dbo");
     Table("CustomerAddress");
     Id(x => x.CustomerAddressId);
     Map(x => x.FromDate)
         .Not.Nullable();
     Map(x => x.ToDate);
     HasOne(x => x.Address)
     .Constrained()
     .ForeignKey();
 }

Such mapping left in my case one side empty, so I modified property setter for child entity (CustomerAddress):

public virtual Address Address
{ 
    get { return _address; }
    set 
    {
        _address = value;
        value.CustomerAddress = this;
    }
}

After these actions one-to-one worked fine) Hope it will help you to solve the problem.