Domanda

I have a class hierarchy that conceptually looks similar to this:

enter image description here

That is, there's an abstract base class (Relation) and a couple of derived classes. In practice, Customer and Supplier share a lot of code, so I refactored the commonoalities into an abstract class BusinessContact. Now the actual class hierarchy looks like this:

enter image description here

Or in code:

public abstract class Relation
{
    public virtual int Id { get; set; }
}

public class ContactPerson : Relation
{
    public virtual string PhoneNumber { get; set; }
}

public abstract class BusinessContact : Relation
{
    public virtual string Name { get; set; }
}

public class Customer : BusinessContact
{
    public virtual string CustomerNumber { get; set; } 
}

public class Supplier : BusinessContact
{
    public virtual string SupplierNumber { get; set; }
}

I'd like to map this hierarchy to four tables (Relation, ContactPerson, Customer and Supplier) using joined-subclasses in NHibernate, using mapping-by-code (ModelMapper). My mapping looks like this:

var mapper = new ModelMapper();

mapper.Class<Relation>(map =>
{
    map.Id(x => x.Id, id => id.Generator(Generators.Native));
});

mapper.JoinedSubclass<ContactPerson>(map =>
{
    map.Key(key => key.Column("Id"));
    map.Property(x => x.PhoneNumber);
});

mapper.JoinedSubclass<Customer>(map =>
{
    map.Key(key => key.Column("Id"));
    map.Property(x => x.Name);
    map.Property(x => x.CustomerNumber);
});

mapper.JoinedSubclass<Supplier>(map =>
{
    map.Key(key => key.Column("Id"));
    map.Property(x => x.Name);
    map.Property(x => x.SupplierNumber);
});

However, as soon as I try to add the mapping to the Configuration I get an exception:

NHibernate.MappingException: Cannot extend unmapped class: BusinessContact

I basically understand why this happens. The generated mapping looks like this:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" namespace="JoinedSubClassMapping" assembly="JoinedSubClassMapping" xmlns="urn:nhib    ernate-mapping-2.2">
  <class name="Relation" abstract="true">
    <id name="Id" type="Int32">
      <generator class="native" />
    </id>
  </class>
  <joined-subclass name="ContactPerson" extends="Relation">
    <key column="Id" />
    <property name="PhoneNumber" />
  </joined-subclass>
  <joined-subclass name="Customer" extends="BusinessContact">
    <key column="Id" />
    <property name="CustomerNumber" />
  </joined-subclass>
  <joined-subclass name="Supplier" extends="BusinessContact">
    <key column="Id" />
    <property name="SupplierNumber" />
  </joined-subclass>
</hibernate-mapping>

Customer and Supplier define BusinessContact in their extends attribute, as if BusinessContact was a "normal" entity in the model. As there's no mapping for BusinessContact, this fails, or course. Note that the "Name" property (defined in BusinessContact does not appear in the mapping either.

What I want the mapping to look like is this:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" namespace="JoinedSubClassMapping" assembly="JoinedSubClassMapping" xmlns="urn:nhibernate-mapping-2.2">
  <class name="Relation" abstract="true">
    <id name="Id" type="Int32">
      <generator class="native" />
    </id>
  </class>
  <joined-subclass name="ContactPerson" extends="Relation">
    <key column="Id" />
    <property name="PhoneNumber" />
  </joined-subclass>
  <joined-subclass name="Customer" extends="Relation">
    <key column="Id" />
    <property name="CustomerNumber" />
    <property name="Name" />
  </joined-subclass>
  <joined-subclass name="Supplier" extends="Relation">
    <key column="Id" />
    <property name="SupplierNumber" />
    <property name="Name" />
  </joined-subclass>
</hibernate-mapping>

That is, make Supplier and Customer extend Relation and include all the mapped properties of the (otherwise unmapped) BusinessContact class.

How can I achieve this?

È stato utile?

Soluzione

Here is a solution:

class MyInspector : ExplicitlyDeclaredModel {
    public override bool IsEntity(Type type) {
        if (type == typeof (BusinessContact))
            return false;
        return base.IsEntity(type);
    }
}

var mapper = new ModelMapper(new MyInspector());
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top