Смешивание отображения наследования Nhibernate Тип-на-Иерархия с Типом-на-Класс? - PullRequest
1 голос
/ 16 февраля 2011

Я пытаюсь отобразить эти классы:

public interface IBusinessObject
{
    Guid Id { get; set; }
}
public class Product
{
    public virtual Guid Id { get; set; }
    public virtual int ProductTypeId { get; set; }
}
public class ProductWeSell : Product, IBusinessObject
{
}
public class ProductWeDontSell : Product
{
}

В базу данных с 2 таблицами:

[BusinessObject] COLUMNS ([Id])
[Product] COLUMNS ([Id], [ProdyctTypeId])

Я хочу иметь тип для класса для BusinessObject и тип для иерархии с продуктом. Это должно привести к такому поведению:

  • Добавить продукт: INSERT INTO Product {Guid), null}
  • Добавить товарWeDontSell: INSERT INTO Product {Guid, 2}
  • Добавить ProductWeSell: INSERT INTO BusinessObject {Guid}; Вставить в продукт {SameGuid, 1}

По логике отображения hbm должны быть:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class xmlns="urn:nhibernate-mapping-2.2" name="IBusinessObject" table="BusinessObject">
    <joined-subclass name="ProductWeSell" table="Product"/>
  </class>
</hibernate-mapping>

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class xmlns="urn:nhibernate-mapping-2.2" discriminator-value="null" name="Product" table="Product">
    <discriminator type="String">
      <column name="ProductTypeId" not-null="false" />
    </discriminator>
    <subclass name="ProductWeDontSell" discriminator-value="2" />
    <subclass name="ProductWeSell" discriminator-value="1" />
  </class>
</hibernate-mapping>

Но я получаю {"Дублирующее отображение класса / сущности ProductWeSell"}.

Ответы [ 2 ]

1 голос
/ 16 февраля 2011

Я вполне уверен, что с Fluent NHibernate это не может быть сделано. Я создал следующую TestFixture, пока пытался придумать способ. Также я не уверен, что вы пытаетесь отобразить. IBusinessObject кажется избыточным, если вы собираетесь использовать его для каждой сущности в системе (CreateQuery («от объекта») будет возвращать каждую сущность, наследуемую от объекта, т.е. всего)

Примечание. В настоящее время это не выполняется в запросе IBusinessObject (как следует, так как он не отображается). Я не совсем уверен, почему это не работает без сопоставления интерфейса IBusinessObject, так как неявный полиморфизм, кажется, должен покрывать это (см .: http://nhibernate.info/doc/nh/en/index.html#inheritace-mixingpolymorphism).

[TestFixture]
public class TestFixture
{

    private ISessionFactory _sessionFactory;
    private ISession _session;
    [SetUp]
    public void Setup()
    {
        var fluentConfig = Fluently.Configure().Database(() => SQLiteConfiguration.Standard.InMemory().Provider<TestConnectionProvider>())
                                   .Mappings(x=>x.FluentMappings.Add<ProductMap>()
                                                                .Add<ProductWeSellMap>()
                                                                .Add<ProductWeDontSellMap>());
        var nhConfig = fluentConfig.BuildConfiguration();
        _sessionFactory = fluentConfig.BuildSessionFactory();

        var schema = new SchemaExport(nhConfig);
        schema.Execute(false, true, false);

        _session = _sessionFactory.OpenSession();
    }

    [Test]
    public void SomeTest()
    {
        using (var itx = this._session.BeginTransaction())
        {
            var productSold = new ProductWeSell();
            var productNotSold = new ProductWeDontSell();
            _session.Save(productNotSold);
            _session.Save(productSold);
            itx.Commit();
        }

        using (var itx = this._session.BeginTransaction())
        {
            Assert.That(_session.CreateQuery("from ProductWeSell").List(), Has.Count.EqualTo(1));
            Assert.That(_session.CreateQuery("from ProductWeDontSell").List(), Has.Count.EqualTo(1));
            Assert.That(_session.CreateQuery("from IBusinessObject").List(), Has.Count.EqualTo(1));
            Assert.That(_session.CreateQuery("from Product").List(), Has.Count.EqualTo(2));
        }
    }
}

public interface IBusinessObject
{
    Guid Id { get; set; }
}

public class Product
{
    public virtual Guid Id { get; set; }
    public virtual int ProductTypeId { get; set; }
}
public class ProductMap : ClassMap<Product>
{
    public ProductMap()
    {
        this.Id(x => x.Id);
        this.DiscriminateSubClassesOnColumn("ProductTypeId");
    }
}

public class ProductWeSell : Product, IBusinessObject
{
    public const int ProductWeSellTypeId = 1;
}

public class ProductWeSellMap : SubclassMap<ProductWeSell>
{
    public ProductWeSellMap()
    {
        this.DiscriminatorValue(ProductWeSell.ProductWeSellTypeId);
    }
}

public class ProductWeDontSell : Product
{
    public const int ProductWeDontSellTypeId = 2;
}

public class ProductWeDontSellMap : SubclassMap<ProductWeDontSell>
{
    public ProductWeDontSellMap()
    {
        this.DiscriminatorValue(ProductWeDontSell.ProductWeDontSellTypeId);
    }
}

Это производит следующее отображение HBM:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
  <class xmlns="urn:nhibernate-mapping-2.2" mutable="true" name="CellTester.Test.Database.Product, Test, Version=2.0.0.3, Culture=neutral, PublicKeyToken=a15dc1b99998d28b" table="`Product`">
    <id name="Id" type="System.Guid, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Id" />
      <generator class="guid.comb" />
    </id>
    <discriminator type="String">
      <column name="ProductTypeId" />
    </discriminator>
    <subclass name="ProductWeSell, Test, Version=2.0.0.3, Culture=neutral, PublicKeyToken=a15dc1b99998d28b" discriminator-value="1" />
    <subclass name="ProductWeDontSell, Test, Version=2.0.0.3, Culture=neutral, PublicKeyToken=a15dc1b99998d28b" discriminator-value="2" />
  </class>
</hibernate-mapping>
0 голосов
/ 18 февраля 2011

Я пришел к интересному выводу. Я решил изменить свою архитектуру и использовать отдельные классы для уровня доступа к данным и уровня пользовательского интерфейса домена, я просто конвертирую свои объекты, когда они пересекают уровень. В любом случае хорошей практикой является разделение доступа к данным и пользовательского интерфейса. Таким образом, моя модель доступа к данным теперь довольно проста без какого-либо наследования, наследование появляется только на уровне доменного интерфейса.

...