【问题标题】:How to persist a subset of an object instead of the whole object?如何持久化对象的子集而不是整个对象?
【发布时间】:2015-08-20 01:33:57
【问题描述】:

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

简介:

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

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

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

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

我不想在我的代码中包含上述结构,因此为 Orders 创建了一个视图,以便我可以在 NHibernate 中映射我的 Order,然后它有一个 OrderLines 的集合/包,这使得更多感觉。

映射:(简化)

<class name="Order" table="[view_Orders]">
    <bag name="OrderLines">
</class>

<class name="OrderLine" table="OrderLines" />

问题:

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

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

我的 NHibernate 映射构造为一个 Order 对象,该对象具有 OrderLine 对象的“集合或包”。理想情况下,我希望 NHibernate 只保留 OrderLine 对象集而不是整个对象。

有没有办法做到这一点?我曾尝试使用不同的锁定模式锁定对象,但对我没有帮助。

【问题讨论】:

  • 看来您正在尝试做的事情应该可行。异常表明 NHibernate 正在尝试对映射到不可更新视图的 Order 实体执行 UPDATE。 NHibernate 只会在它认为实体是脏的时才会这样做,在 OrderLines 集合之外。您应该检查您的其他映射属性。或许可以尝试使用像 NHProf 这样的分析器来查看发生了什么变化。
  • 没错。我不想更新我的订单,因为它映射到不可更新的视图。相反,我只想更新子对象,即 OrderLines 包。我一直在使用 NHProfiler,上面的异常基本上是通过 NHibernate 传递的 SQL 异常。

标签: nhibernate nhibernate-mapping


【解决方案1】:

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

不可变类 mutable="false" 可能不会被应用程序更新或删除。这允许 NHibernate 进行一些小的性能优化。

要避免插入,您可以使用以下语句(使用 proyection 而不是 insert 命令,不要忘记使用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>

【讨论】:

    【解决方案2】:

    如果我确实了解您的问题,解决方案非常简单。我们只需用 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

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

    &lt;class name="Eg.Immutable" mutable="false"&gt;

    【讨论】:

    • 您好 Radim,非常感谢您的帮助。我已经尝试过设置 mutable="false" 没有任何成功。我尝试使用动态更新,但仍然遇到相同的错误。我上面描述的错误与数据插入有关,而不是与更新有关,如果我正确的话,我相信你的例子是针对的?
    • 是的,正如我所说,mutable="false" 不是这里的解决方案。但是将所有与视图相关的属性标记为update="false" 将起作用。只是&lt;bag&gt; 将被保留......因为......如果你说你已经映射了视图 - 我们必须谈论更新。所以,正如你所描述的 (如果我没看错的话) - 我们需要在更新期间只保留收集。在这种情况下,甚至可以插入该集合中的项目。但是将全新的记录插入父视图......根据您的场景没有意义。这是我检查并正在工作的内容.. 还是?
    • 我的意思是你的问题的一部分 "...理想情况下,我希望 NHibernate 只保留 OrderLine 对象集而不是整个对象..." 所以,如果我们确实有现有记录(由视图表示的记录,映射为父对象),我们将只插入 OrderLines ...并且上述答案将支持该解决方案。订单已经存在(不是由 NHibernate 更新)OrderLines 中的所有项目都是完全可管理的......
    猜你喜欢
    • 2017-04-03
    • 1970-01-01
    • 2011-07-25
    • 2015-05-01
    • 2020-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多