我正在努力解决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
个对象而不是整个对象。
有没有办法实现这个目标?我尝试使用不同的锁定模式锁定对象,但它没有帮助我。
答案 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"
,但它不会在这里...作为
上面提到的解决方案(很遗憾,因为那会更多
优雅,但没有按预期工作......)。参见:
如果您的应用程序需要读取但从不修改持久化类的实例,则可以使用只读缓存。这是最简单,性能最佳的策略。它甚至可以非常安全地用于集群。
<class name="Eg.Immutable" mutable="false">