我有一个使用Nhibernate保存的对象。该对象使用复合键,声明如下:
CompositeId()
.KeyProperty(x => x.CreditorName)
.KeyProperty(x => x.CreditorIBAN)
.KeyReference(x => x.Config, "ProfileName");
Map(x => x.ID, "ID").ReadOnly();
Map(x => x.CreationDate, "CreationDate").Default(null);
Map(x => x.ContractReference, "ContractReference");
Map(x => x.CreditorBIC, "CreditorBIC");
References<C_ContractType>(x => x.ContractType, "ContractType_ID");
References<C_Country>(x => x.CreditorCountry, "CreditorCountry");
Table("Creditor");
Cache.ReadWrite();
我们可以毫无问题地保存,但是当我们尝试使用Session.SaveOrUpdate(entity);
更新字段(无论哪一个)时,没有任何操作(没有更新),没有错误消息。
我们错过了什么吗?谢谢你的帮助!
- 编辑 -
我在更新方法之后添加Session.Flush()
,它更好一点,因为我可以更新任何值,除了密钥中的值(CreditorName和CreditorIBAN)。有什么想法吗?
答案 0 :(得分:2)
<强>予。 PERSISTING ,执行sql write命令
正如评论中所讨论的那样,我们需要做的第一件事就是用 ISession.Flush()
(引用一些)
...
除非明确表示Flush(),否则绝对无法保证Session何时执行ADO.NET调用,只保证执行它们的顺序。 ...
正如这里所讨论的那样
How to change default FlushMode to Commit in C#?
我们可以在会话创建期间分配默认的刷新模式
var session = SessionFactory.OpenSession();
session.FlushMode = FlushMode.Commit;
确保在提交交易后调用它或明确调用它 anytime
我们需要
Session.SaveOrUpdate(entity);
Session.Flush();
<强> II。密钥/ ID更改已经存在,而不是瞬态实体
这是设计意图,意图是不可能的。由于数据库Key
,C#运行时实体Id
是指向实例的 数据层 指针。我们不应该使用这些,我们不应该试着考虑它们
我们的实体应该通过引用进行管理:
var entity = ...;
entity.ContractType = someContractType;
entity.CreditorCountry = defaultCountry;
...
这样我们就可以在Flush()上分配db键,表示为Ids ...而不提及它们。
这就是为什么我们不应该考虑改变它们的能力。
我们能做的最好 - 就是不使用复合键 - 并使用
数据库中的代理键是建模世界中的实体或数据库中的对象的唯一标识符。代理键不是从应用程序数据派生的,与从应用程序数据派生的自然(或业务)密钥不同。
使用SQL Server,很容易引入IDENTITY(1,1)的新列...只需使用ALTER TABLE TheID INT NOT NULL IDENTITY(1,1)
...并在那里
将所有复合部件重新映射到属性(.Map()
或.References()
),然后您可以更改任何内容
我可以理解这不是理想的答案,但我强烈建议至少要考虑一下。简单地说,
密钥只应生成一次。然后永远保持不变...或删除其行/实例
答案 1 :(得分:0)