有没有理由不对NHibernate使用dynamic-insert
/ dynamic-update
?我问的唯一原因是它似乎是我想要启用的默认设置,而不是我必须配置的东西。
使用这些动态属性时是否有任何问题需要注意?
答案 0 :(得分:26)
对于某些实体,您可以通过动态更新创建无效状态。假设您有Class
Boolean
属性A
和逻辑依赖Integer
属性B
。如果属性A
为True
,则属性B
只能为负数,而如果属性A
为False
,则为属性B
只能是一个正数。
假设两个用户在给定的时间跨度内都与该类的实例进行交互。要开始,用户Alice和Bob都会从数据库中实现此类,初始值为A
= True且B
= -50
Database Alice Bob
A: True A: True A: True
B: -50 B: -50 B: -50
VALID VALID VALID
用户Alice将A
更改为False
并将B
更改为125,并将其提交到数据库。现在我们遇到这种情况:
Database Alice Bob
A: False A: False A: True
B: 125 B: 125 B: -50
VALID VALID VALID
用户Bob不会更改A
,而是将B
更改为-75,然后将其提交到数据库。如果启用了动态更新,则NHibernate会发现Bob仅将B
更改为-75,并发出仅编辑B
值的动态更新。如果您在服务器上进行SQL验证以防止B
为负,除非A
为真,那么您在此处会收到SQL错误,但是假设您没有复制所有业务逻辑你的SQL表。以下是结果数据:
Database Alice Bob
A: False A: False A: True
B: -75 B: 125 B: -75
INVALID VALID VALID
Alice和Bob都有有效状态,但数据库现在处于无效状态!用户查理出现并尝试实现此记录:
Database Alice Bob Charlie
A: False A: False A: True A: False
B: -75 B: 125 B: -75 B: -75
INVALID VALID VALID INVALID
当NHibernate尝试设置类的新实例的B属性时,Charlie可能会从您的应用程序中获得验证错误。
因此,当您具有逻辑依赖属性时,您必须制定一些策略来避免这种情况。一种可能性是简单地为此实体启用select-before-update
。这可能会导致一些额外的数据库调用和性能稍慢。另一个是在NHibernate中使用版本控制,这意味着当Bob试图保存他的记录时,NHibernate的插入查询不会触发任何写入并抛出过时的数据异常(可以优雅地处理)。您还可以在数据库中编写类的逻辑要求,但是您必须小心谨慎,以确保数据库和程序在时间的推移下具有相同的编码要求,并且您将拥有多个位置在需求发生变化时进行更改,这并不总是值得开销。
因此,简而言之,在许多情况下,开发人员必须仔细处理动态更新的细节,这就是默认情况下不启用的原因。当您打开它时,请考虑对您的实体进行部分更新是否会导致问题,如果是,请使用我建议的一种缓解策略来防范该问题。
答案 1 :(得分:6)
动态插入和更新的性能成本很低,因为NHibernate每次都必须构造SQL而不是缓存它。我不知道数据库方面是否有成本。动态插入和更新非常便于进行故障排除和分析。如果我能够衡量一个有意义的性能影响,我会在开发和生产中将其打开。
您可能会遇到侦听器和拦截器的问题,请参阅this question。
我在我的NHibernate应用程序中打开它没有任何问题。我的答案是否定的,没有充分的理由不使用它。