是否可以使用NHibernate将多个表映射到单个域模型?

时间:2009-07-22 00:49:29

标签: nhibernate mapping union

是否可以使用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;
}

2 个答案:

答案 0 :(得分:4)

是的,您可以使用许多选项来执行您想要的操作。 Ayende Rahien有一个great demonstration of the options用于表继承和结果表结构。

使用具有抽象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>

 <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>

也有单独的表,但不使用联合进行查询。

查看article,它可能会有很大帮助。


修改

有一条关于不想投的评论,但它现在已经消失了。我不确定它是否被删除或是否是SO问题......

如果BaseOrder.Status是虚拟属性,您应该能够传递BaseOrder而不需要强制转换。您必须维护额外的类层次结构,但您仍然可以一起查询它们,并且在大多数情况下,应用程序的其余部分不需要了解子类。

祝你好运!

答案 1 :(得分:-1)

您是否考虑过使用[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