如何持久化对象的子集而不是整个对象?

时间:2015-08-11 06:51:24

标签: nhibernate nhibernate-mapping

我正在努力解决NHibernate相关的问题,我可以使用一些输入。

简介

我有一个遗留数据库,其中尚未真正应用关系概念。

在数据库中,我有一个OrderLine表,其中包含订单行的数据。

除此之外,该表还包含具有Order特定信息的所有列。例如,这可以是客户的订单号。

E.x。如果我有10个订单行 - 那么我的OrderLines表中有10行,每行都包含所有Order个特定数据,例如订单号或客户信息。

我不想在我的代码中使用上述结构,因此为Orders创建了一个视图,以便我可以在NHibernate中映射我的Order,然后它有一个{{1}的set / bag这更有意义。

映射:(简化)

OrderLines

问题:

视图的复杂性使得无法保存到视图中。尝试NHibernates时抛出此异常:

  

NHibernate.Exceptions.GenericADOException:无法插入:XXX ---> System.Data.SqlClient.SqlException:视图或函数'view_Orders'不可更新,因为修改会影响多个基表。

我的NHibernate映射构造为<class name="Order" table="[view_Orders]"> <bag name="OrderLines"> </class> <class name="OrderLine" table="OrderLines" /> 对象,其中包含Order个对象的“集合或包”。理想情况下,我希望NHibernate只保留OrderLine个对象而不是整个对象。

有没有办法实现这个目标?我尝试使用不同的锁定模式锁定对象,但它没有帮助我。

2 个答案:

答案 0 :(得分:3)

您可以使用mutable="false"来避免更新和删除,因为article说:

  

应用程序可能无法更新或删除不可变类 mutable =&#34; false&#34; 。这允许NHibernate进行一些小的性能优化。

要避免插入,您可以使用以下语句(使用 proyection 而不是插入命令,不要忘记使用check="none"):

<sql-insert check="none">SELECT 1</sql-insert>

这是一个经过测试的例子:

<class name="Order" table="[view_Orders]" mutable="false">
  <id name="OrderId" type="System.Guid">
    <generator class="guid.comb"/> <!-- Change as you need -->
  </id>

  <!-- Other properties -->
  <!-- <property name="GrandTotal"/> -->

  <set name="OrderLines" lazy="true" inverse="true" cascade="all-delete-orphan">
    <key column="OrderId"/>
    <one-to-many class="OrderLine"/>
  </set>

  <sql-insert check="none">SELECT 1</sql-insert>
</class>

<class name="OrderLine" table="OrderLine">
  <id name="OrderLineId" type="System.Guid">
    <generator class="guid.comb"/> <!-- Change as you need -->
  </id>

  <!-- Other properties -->
  <!-- <property name="OrderId"/>
  <property name="GrandTotal"/>/> --> 

</class>

答案 1 :(得分:1)

如果我确实理解您的问题,解决方案非常简单。我们只需使用 dynamic-update="true"

标记根对象
<class name="Order" table="[view_Orders]" dynamic-update="true">
    ...
</class>

然后将 update="false" 应用于映射到视图的Order类中的每个属性或引用:

...
<property name="Code"       update="false"/>
...
<many-to-one name="Country" update="false />

但我们的系列需要标准,甚至是级联映射:

<class name="Order" table="[view_Orders]" dynamic-update="true">
    <bag name="OrderLines" 
         lazy="true" 
         inverse="true" 
         batch-size="25" 
         cascade="all-delete-orphan" >
      ...
     </bag>
     ... // other stuff is update="false"
</class>

现在这样的代码会管理 OrderLines ,而不会对根对象Order

执行任何更新
var session = ... // get ISession 
// load root
var root = session.Get<Order>(123);

// if needed change existing line (pretend there is one)
root.OrderLines[0].Amount = 100;

// add new
var newOrder = ... // new order
root.OrderLines.Add(newOrder);

session.Save(root);
session.Flush();

就是这样。根对象上的级联正在做我们需要的事情,而update =“false”没有更新它...

注意:只是有趣的注意 - 还有类和集合 设置 mutable="false" ,但它不会在这里...作为 上面提到的解决方案(很遗憾,因为那会更多 优雅,但没有按预期工作......)。参见:

19.2.2. Strategy: read only

  

如果您的应用程序需要读取但从不修改持久化类的实例,则可以使用只读缓存。这是最简单,性能最佳的策略。它甚至可以非常安全地用于集群。

     

<class name="Eg.Immutable" mutable="false">

相关问题