开发者

SubClass mapping with multipe "roles"

开发者 https://www.devze.com 2023-03-26 19:39 出处:网络
a tricky problem - please bear with me. Any help greatly appreciated. I have a table/class Contact (PK Id) and two derived Client and Debtor (PK and FK ContactId). The 4th table Case has foreign keys

a tricky problem - please bear with me. Any help greatly appreciated.

I have a table/class Contact (PK Id) and two derived Client and Debtor (PK and FK ContactId). The 4th table Case has foreign keys to Debtor and Client (mappings below).

Everything worked fine at first. But then I hit some data where the same Contact is a Client in one Case but a Debtor in another. If those are read in one nhibernate query like Session.Query<Case>().Fetch(c => c.Debtor).Fetch(c => c.Client) there is a

NHibernate.WrongClassException
    "Object with id: {someGuid...} was not of the specified subclass: Client 
    (loading object was of wrong class [Debtor])

Seems like the session first level cache is recognizing the record by it's Id and tr开发者_高级运维ies to avoid reading the data from the sql result set. Of course the cast NH thinks is necessary for the reuse fails.

Unfortunately changing the DB schema is not an option. It's a legacy system. (an the schema is ok and clean IMO)

Don't know if it is important: The class Contact is not abstract. There are Contacts used who are neither Client nor Debtor.

Is there any chance of getting this to work with these multi-role-contacts? Thanks in advance.

public partial class ContactMap : ClassMap<Contact>
{
    public ContactMap()
    {
    Id(x=>x.Id).GeneratedBy.Guid();
    Map(x=>x.FirstName);
    Map(x=>x.Name1).Not.Nullable();
        ...
    }
}
public class DebtorMap : SubclassMap<Debtor>
{

    public DebtorMap()
    {
        KeyColumn("ContactID");
        Table("[dbo].[Debtor]");
        Map(x => x.MaritalStatus);
        ...
    }
}

public partial class ClientMap : SubclassMap<Client>
{

    public ClientMap()
    {
        KeyColumn("ContactID");            
        Map(x => x.ClientNo).Not.Nullable();
        ...
    }
}

public partial class CaseMap : ClassMap<Case>
   public CaseMap()
   {
       ...
       References<Client>(x=>x.Client)
       References<Debtor>(x=>x.Debtor)
       ...
    }    


If you can add a view to the schema, you can create a view called Roles which unions both Client and Debtor records. You can then change your object model to represent roles:

class Contact
{
    public virtual Guid Id { get; set; }
    public virtual string FirstName { get; set; }
    public virtual ICollection<Role> Roles { get; private set; }
}

class Role
{
    public virtual Guid Id { get; set; }
}

class Client : Role
{
    public virtual string ClientNo { get; set; }
}

class Debtor : Role
{
    public virtual string MaritalStatus { get; set; }
}

class ContactMap : FluentNHibernate.Mapping.ClassMap<Contact>
{
    public ContactMap()
    {
        Table("dbo.Contacts");
        Id(x => x.Id).GeneratedBy.GuidComb();
        Map(x => x.FirstName);
        HasMany(x => x.Roles)
            .KeyColumn("ContactId")
            .Not.LazyLoad()
            .Fetch.Join();
    }
}

class RoleMap : FluentNHibernate.Mapping.ClassMap<Role>
{
    public RoleMap()
    {
        Table("dbo.Roles");
        Id(x => x.Id).GeneratedBy.GuidComb();
        this.Polymorphism.Implicit();
    }
}

class ClientMap : FluentNHibernate.Mapping.SubclassMap<Client>
{
    public ClientMap()
    {
        Table("dbo.Clients");
        KeyColumn("Id");
        Map(x => x.ClientNo);
    }
}

class DebtorMap : FluentNHibernate.Mapping.SubclassMap<Debtor>
{
    public DebtorMap()
    {
        Table("dbo.Debtors");
        KeyColumn("Id");
        Map(x => x.MaritalStatus);
    }
}

Since the Contact table does now share a PK with Client and Debtor tables this should work. The Roles view would look something like this:

create view dbo.Roles as

select 
    Id,
    ContactId
from dbo.Clients

union all

select 
    Id,
    ContactId
from dbo.Debtors
0

精彩评论

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