Можно ли сопоставить несколько таблиц с одной моделью домена с помощью NHibernate?

Можно ли сопоставить несколько таблиц с одной моделью домена с помощью NHibernate? По сути, это UNION, что-то вроде того, что показано ниже, но я не уверен, как создавать модели предметной области на C # и сопоставления NHibernate.

В основном у меня есть 1 абстрактный класс и 2 конкретных класса. Каждый конкретный класс можно сопоставить с одной таблицей в базе данных.

Оператор SQL:

SELECT  *
FROM    InCompleOrders

UNION

SELECT  *
FROM    CompleteOrders 

В данный момент я делаю так:

Модели предметной области C #:

public enum Status
{
  InComplete = 1,
  Pending = 2,
  Complete = 3
}
public abstract class BaseOrder : Entity
{
  public string Property1 {get;set;}
  public string Property2 {get;set;}
  public string Property3 {get;set;}


  public Status Status {get;set;}
  public string Reference {get;set;} //this is unique
}
public class InCompleteOrder : BaseOrder
{
  public override Status Status
  {
    get { return Status.InComplete; }
  }
}
public class Order : BaseOrder
{
  public DateTime DeliveredOn {get;set;}
  public DateTime PaidOn {get;set;}
}

Таблицы базы данных:

InCompleOrders table
  InCompleOrderId INT PK
  Property1 varchar(255) NULL
  Property2 varchar(255) NULL
  Property3 varchar(255) NULL

CompleteOrders table
  CompleteOrderId INT PK
  Status INT
  Property1 varchar(255) NOT NULL
  Property2 varchar(255) NOT NULL
  Property3 varchar(255) NOT NULL
  DeliveredOn datetime NOT NULL
  PaidOn datetime NOT NULL

Отображение NHibernate:

<class name="Order" table="CompleteOrders">
  <id name="Id" column="CompleteOrderId" type="int">
    <generator class ="hilo"></generator>
  </id>
  <property name="DeliveredOn" column="DeliveredOn" not-null="true" type="DateTime" />
  <property name="PaidOn" column="PaidOn" not-null="true" type="DateTime" />

  <property name="Property1" column="Property1" not-null="true" type="string" />
  <property name="Property2" column="Property2" not-null="true" type="string" />
  <property name="Property3" column="Property3" not-null="true" type="string" />
</class>

<class name="InCompleteOrder " table="InCompleOrders">
  <id name="Id" column="InCompleOrderId" type="int">
    <generator class ="hilo"></generator>
  </id>

  <property name="Property1" column="Property1" not-null="false" type="string" />
  <property name="Property2" column="Property2" not-null="false" type="string" />
  <property name="Property3" column="Property3" not-null="false" type="string" />

</class>

Я не хочу делать такие вещи, как:

public BaseOrder GetByReference (string reference)
{
  BaseOrder bo;

  var repoOrder = new Repository<Order>();
  bo = repoOrder.FindOne(query); 
  //query = Restrictions.Eq("Reference", reference)

  if (bo == null)
  {
    var repoInCompOrder = new Repository<InCompleteOrder>();
    bo = repoInCompOrder.FindOne(query); 
    //query = Restrictions.Eq("Reference", reference)
  }

  return bo;
}

И я хочу уметь:

public Order GetByReference (string reference)
{
  var repoOrder = new Repository<Order>();
  var bo = repoOrder.FindOne(query); 
  //query = Restrictions.Eq("Reference", reference) //reference = "abc"
  //and this will generate a SQL similar to:
  //
  //SELECT CompleteOrderId
  //       , Status 
  //FROM   CompleteOrders 
  //WHERE  Reference = 'abc'
  //
  //UNION
  //
  //SELECT InCompleOrderId 
  //       , 1 AS 'Status'
  //FROM   InCompleOrders 
  //WHERE  Reference = 'abc'

  return bo;
}

person Community    schedule 22.07.2009    source источник


Ответы (2)


Да, есть несколько вариантов, с помощью которых вы можете делать то, что хотите. У Айенде Рахиен есть отличная демонстрация возможностей для наследования таблиц и результирующих структур таблиц.

Используя иерархию классов, которая имеет абстрактный BaseOrder в качестве родительского для CompleteOrder и IncompleteOrder, случай объединения выглядит следующим образом:

<class name="CompleteOrder" table="CompleteOrders">
    <id name="Id">
        <generator class="identity"/>
    </id>
    <property name="Status"/>
</class>

<class name="IncompleteOrder" table="IncompleteOrders">
    <id name="Id">
        <generator class="identity"/>
    </id>
</class>

or

 <class name="BaseOrder" abstract="true" table="Orders">
    <id name="Id">
        <generator class="hilo"/>
    </id>

    <union-subclass table="CompleteOrders" name="CompleteOrder">
        <property name="Status"/>
    </union-subclass>

    <union-subclass table="IncompleteOrders" name="IncompleteOrder">
    </union-subclass>
</class>

который также имеет отдельные таблицы, но не использует объединение для запроса.

Ознакомьтесь с статьей, это вероятно, очень поможет.


изменить:

Был комментарий о том, что я не хочу участвовать в кастинге, но его больше нет. Я не уверен, был ли он удален или это была ТАКАЯ проблема ...

Если BaseOrder.Status является виртуальным свойством, вы должны иметь возможность передавать BaseOrder и не требовать преобразования. Вам придется поддерживать дополнительную иерархию классов, но вы все равно можете запрашивать их вместе, и, по большей части, остальной части приложения не нужно знать о подклассах.

Удачи!

person Community    schedule 24.07.2009
comment
Я прочитал ссылку, однако обнаружил, что в данном примере есть таблица для абстрактного класса под названием «Стороны», где в моем случае этой таблицы нет. - person Jeff; 24.07.2009
comment
Проблема с кастингом заключалась в том, что если у меня есть разные свойства в дочернем классе (InCompleteOrder и Order), то мне нужно будет выполнить приведение между ними. Но я не думаю, что здесь есть какое-то решение. - person Jeff; 24.07.2009
comment
Привет, Джеффри, есть 2 примера с базовой таблицей и 2 без нее. Взгляните на 2-й и 4-й примеры. - person Steven Lyons; 24.07.2009
comment
Спасибо, что проявили ко мне терпение. В качестве начала у меня есть второй пример, работающий здесь. - person Jeff; 24.07.2009
comment
Теперь мне нужно выяснить, как сопоставить коллекцию элементов для каждого конкретного класса, где с точки зрения базы данных элементы разделены на таблицу CompleteItems и таблицу InCompleteItems. Такой дерьмовый дизайн базы данных убивает новичков в NHibernate вроде меня. - person Jeff; 24.07.2009
comment
Я не могу использовать 4-й пример, поскольку имена столбцов PK, конкретные таблицы разные! Или, может быть, это еще далеко, чтобы обойти это. - person Jeff; 24.07.2009
comment
Я не использовал его, но, глядя на ссылку, я понял, что унаследованные свойства должны иметь одно и то же имя. Вы также можете попробовать группу nhusers Google [groups.google.com/group/nhusers/estive, если у вас есть вопрос, на который здесь нет ответа. - person Steven Lyons; 24.07.2009
comment
ссылки теперь не работают - person Jon; 29.09.2016

Вы рассматривали возможность использования [view][1]?

Вы можете определить свой view следующим образом:

CREATE VIEW AllOrders AS
  SELECT CompleteOrderId
         , Status 
  FROM   CompleteOrders 
  WHERE  Reference = 'abc'

  UNION

  SELECT InCompleOrderId 
         , 1 AS 'Status'
  FROM   InCompleOrders 
  WHERE  Reference = 'abc'

С точки зрения Hibernate (и, предположительно, NHibernate) AllOrders - это просто еще одна таблица для сопоставления вашего объекта домена.

Одно предостережение заключается в том, что вы не сможете выполнять вставки в представление (обновления могут работать, а могут и не работать, я не уверен). Поэтому, если вам нужно выполнить операции записи, вам все равно может потребоваться сопоставление с CompleteOrders и InCompleteOrders независимо.

Изменить: Похоже, я ошибался, говоря, что не могу вставлять данные в представления - http://www.google.com/search?q=insertable%20view

person Community    schedule 24.07.2009