nHibernate 正在尝试 SQL 更新我刚创建的实体,而不是插入?
nHibernate is trying to SQL UPDATE an entity I just created, rather than INSERT?
一个项目参与者可能是多个组的成员,一个组可能有多个项目参与者
我发现当我创建 2 个 ProjectParticipants(有效)然后用 3 个新组 填充 Project.Groups
集合并将参与者添加到相关组(A 组有参与者 1,B 组有参与者 2,C 组有参与者 1 和 2),我遇到 "StaleStateException - Batch update returned unexpected row count from update; actual row count: 0, expected: 3"。我希望 nHibernate 插入新组,但它正在 运行 更新查询并犹豫它们不存在。它没有达到将参与者分配到组的程度
这是映射:
//ProjectMap: A Project..
Id(x => x.Id).GeneratedBy.GuidComb().UnsavedValue(Guid.Empty);
HasMany(x => x.Participants)
.Table("ProjectParticipants")
.KeyColumn("ProjectId")
.ApplyFilter(DeletedDateFilter.FilterName)
.Cascade.AllDeleteOrphan()
.Inverse();
HasMany(x => x.Groups)
.Table("ProjectGroups")
.KeyColumn("ProjectId")
.Cascade.AllDeleteOrphan()
.Inverse();
//ProjectParticipantMap: A ProjectParticipant…
Id(x => x.Id).GeneratedBy.GuidComb().UnsavedValue(Guid.Empty);
References(x => x.Project)
.Column("ProjectId")
.LazyLoad(Laziness.Proxy);
HasManyToMany(x => x.Groups)
.Table("ProjectGroupParticipants")
.ParentKeyColumn("ProjectParticipantId")
.ChildKeyColumn("ProjectGroupId");
//GroupMap: A Group...
Id(e => e.Id).GeneratedBy.Assigned().UnsavedValue(Guid.Empty);
References(e => e.Project)
.Column("ProjectId")
.LazyLoad(Laziness.Proxy);
HasManyToMany(x => x.Participants)
.Table("ProjectGroupParticipants")
.ParentKeyColumn("ProjectGroupId")
.ChildKeyColumn("ProjectParticipantId")
.ApplyChildFilter(DeletedDateFilter.FilterName);
表格是:
[ProjectParticipants] 1-->M [ProjectGroupParticipants] M<--1 [ProjectGroups]
M M
\---------------->1 [Project] 1<--------------------/
这是 nHibernate 运行 中的 SQL:
--presume this is adding the first participant - I find him in the db
INSERT INTO ProjectParticipants (CreatedDate, ModifiedDate, DeletedDate, FirstName, LastName, Timezone, Email, Pseudonym, Role, ProjectId, UserId, MobileNumber, Id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
--presume this is adding the second participant - I find her in the DB
INSERT INTO ProjectParticipants (CreatedDate, ModifiedDate, DeletedDate, FirstName, LastName, Timezone, Email, Pseudonym, Role, ProjectId, UserId, MobileNumber, Id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
--not sure what this is doing
UPDATE Projects SET CreatedDate = ?, ModifiedDate = ?, LogoUrl = ?, LogoFilename = ?, Client = ?, Name = ?, Description = ?, LastAccessedDate = ? WHERE Id = ?
--not sure what this operation is for, but at this point in time NO GROUP EXISTs for this project ID
SELECT … FROM ProjectGroups groups0_ WHERE groups0_.ProjectId=?
--not sure what this is for either?
UPDATE Projects SET CreatedDate = ?, ModifiedDate = ?, LogoUrl = ?, LogoFilename = ?, Client = ?, Name = ?, Description = ?, LastAccessedDate = ? WHERE Id = ?
-- I've no idea why this is an UPDATE instead of an INSERT, but it will certainly update 0 rows instead of X, because no groups exist
UPDATE ProjectGroups SET CreatedDate = ?, ModifiedDate = ?, DeletedDate = ?, Name = ?, ProjectId = ? WHERE Id = ?
Exception thrown: 'NHibernate.StaleStateException' in NHibernate.dll
Batch update returned unexpected row count from update; actual row count: 0; expected: 3
[ UPDATE ProjectGroups SET CreatedDate = @p0, ModifiedDate = @p1, DeletedDate = @p2, Name = @p3, ProjectId = @p4 WHERE Id = @p5 ]
那么为什么 nHibernate 会认为它的本地实体已经保存并因此可以更新?生成的 SQL 应该是一个插入,但我不确定它如何管理本地缓存和数据库之间的同步以了解实体是否已经存在
有点疑惑,这曾经在 NH 2.x 中有效,但自从升级到最新版本 (5.x) 后开始出现此异常。
Slightly puzzled, that this used to work in NH 2.x,
unsaved-value
的处理确实在 5.2 中有了这个 pull request 的改变。
如果我理解正确,这个 PR 修复了一些情况,其中提供的 unsaved-value
映射被分配的标识符忽略。
看来您的实体的 unsaved-value
映射不正确,分配了标识符。根据给定的数据,不清楚您期望 NHibernate 如何确定实体是否是瞬态的。对于您的映射,如果 Id
不等于 Guid.Empty
NHibernate 将为所有级联实体触发 UPDATE
语句,这似乎正是您所看到的行为。
如果您希望它在会话中不存在实体时检查数据库 - 将其设置为 "undefined"
:
Id(x => x.Id).GeneratedBy.GuidComb().UnsavedValue("undefined");
如果您希望它始终保存实体 - 将其设置为 "any"
。
阅读spec with explanations for all other possible values. Also check this similar issue。
一个项目参与者可能是多个组的成员,一个组可能有多个项目参与者
我发现当我创建 2 个 ProjectParticipants(有效)然后用 3 个新组 填充 Project.Groups
集合并将参与者添加到相关组(A 组有参与者 1,B 组有参与者 2,C 组有参与者 1 和 2),我遇到 "StaleStateException - Batch update returned unexpected row count from update; actual row count: 0, expected: 3"。我希望 nHibernate 插入新组,但它正在 运行 更新查询并犹豫它们不存在。它没有达到将参与者分配到组的程度
这是映射:
//ProjectMap: A Project..
Id(x => x.Id).GeneratedBy.GuidComb().UnsavedValue(Guid.Empty);
HasMany(x => x.Participants)
.Table("ProjectParticipants")
.KeyColumn("ProjectId")
.ApplyFilter(DeletedDateFilter.FilterName)
.Cascade.AllDeleteOrphan()
.Inverse();
HasMany(x => x.Groups)
.Table("ProjectGroups")
.KeyColumn("ProjectId")
.Cascade.AllDeleteOrphan()
.Inverse();
//ProjectParticipantMap: A ProjectParticipant…
Id(x => x.Id).GeneratedBy.GuidComb().UnsavedValue(Guid.Empty);
References(x => x.Project)
.Column("ProjectId")
.LazyLoad(Laziness.Proxy);
HasManyToMany(x => x.Groups)
.Table("ProjectGroupParticipants")
.ParentKeyColumn("ProjectParticipantId")
.ChildKeyColumn("ProjectGroupId");
//GroupMap: A Group...
Id(e => e.Id).GeneratedBy.Assigned().UnsavedValue(Guid.Empty);
References(e => e.Project)
.Column("ProjectId")
.LazyLoad(Laziness.Proxy);
HasManyToMany(x => x.Participants)
.Table("ProjectGroupParticipants")
.ParentKeyColumn("ProjectGroupId")
.ChildKeyColumn("ProjectParticipantId")
.ApplyChildFilter(DeletedDateFilter.FilterName);
表格是:
[ProjectParticipants] 1-->M [ProjectGroupParticipants] M<--1 [ProjectGroups]
M M
\---------------->1 [Project] 1<--------------------/
这是 nHibernate 运行 中的 SQL:
--presume this is adding the first participant - I find him in the db
INSERT INTO ProjectParticipants (CreatedDate, ModifiedDate, DeletedDate, FirstName, LastName, Timezone, Email, Pseudonym, Role, ProjectId, UserId, MobileNumber, Id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
--presume this is adding the second participant - I find her in the DB
INSERT INTO ProjectParticipants (CreatedDate, ModifiedDate, DeletedDate, FirstName, LastName, Timezone, Email, Pseudonym, Role, ProjectId, UserId, MobileNumber, Id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
--not sure what this is doing
UPDATE Projects SET CreatedDate = ?, ModifiedDate = ?, LogoUrl = ?, LogoFilename = ?, Client = ?, Name = ?, Description = ?, LastAccessedDate = ? WHERE Id = ?
--not sure what this operation is for, but at this point in time NO GROUP EXISTs for this project ID
SELECT … FROM ProjectGroups groups0_ WHERE groups0_.ProjectId=?
--not sure what this is for either?
UPDATE Projects SET CreatedDate = ?, ModifiedDate = ?, LogoUrl = ?, LogoFilename = ?, Client = ?, Name = ?, Description = ?, LastAccessedDate = ? WHERE Id = ?
-- I've no idea why this is an UPDATE instead of an INSERT, but it will certainly update 0 rows instead of X, because no groups exist
UPDATE ProjectGroups SET CreatedDate = ?, ModifiedDate = ?, DeletedDate = ?, Name = ?, ProjectId = ? WHERE Id = ?
Exception thrown: 'NHibernate.StaleStateException' in NHibernate.dll
Batch update returned unexpected row count from update; actual row count: 0; expected: 3
[ UPDATE ProjectGroups SET CreatedDate = @p0, ModifiedDate = @p1, DeletedDate = @p2, Name = @p3, ProjectId = @p4 WHERE Id = @p5 ]
那么为什么 nHibernate 会认为它的本地实体已经保存并因此可以更新?生成的 SQL 应该是一个插入,但我不确定它如何管理本地缓存和数据库之间的同步以了解实体是否已经存在
有点疑惑,这曾经在 NH 2.x 中有效,但自从升级到最新版本 (5.x) 后开始出现此异常。
Slightly puzzled, that this used to work in NH 2.x,
unsaved-value
的处理确实在 5.2 中有了这个 pull request 的改变。
如果我理解正确,这个 PR 修复了一些情况,其中提供的 unsaved-value
映射被分配的标识符忽略。
看来您的实体的 unsaved-value
映射不正确,分配了标识符。根据给定的数据,不清楚您期望 NHibernate 如何确定实体是否是瞬态的。对于您的映射,如果 Id
不等于 Guid.Empty
NHibernate 将为所有级联实体触发 UPDATE
语句,这似乎正是您所看到的行为。
如果您希望它在会话中不存在实体时检查数据库 - 将其设置为 "undefined"
:
Id(x => x.Id).GeneratedBy.GuidComb().UnsavedValue("undefined");
如果您希望它始终保存实体 - 将其设置为 "any"
。
阅读spec with explanations for all other possible values. Also check this similar issue。