nHibernate试图对我刚刚创建的实体进行SQL UPDATE,而不是INSERT?

时间:2019-05-29 17:23:48

标签: nhibernate

一个项目参与者可能是许多小组的成员,而一个小组可能有很多项目参与者

我发现当我创建2个ProjectParticipant(可行)时,然后用 3个新组填充Project.Groups集合,并将参与者添加到相关组中(组A具有参与者1,组B具有参与者2,组C具有参与者1和2),我遇到“ StaleStateException-批更新从更新返回意外行计数;实际行计数:0,预期:3”。我希望nHibernate插入新的组,但是它正在运行UPDATE查询并阻止它们不存在。不能将参与者分配到组中

以下是映射:

//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认为其本地实体已经被保存过,因此可用于UPDATE?生成的SQL应该是一个插入,但是我不确定它如何管理本地缓存和数据库之间的同步以了解实体是否已经存在

有点困惑,它曾经在NH 2.x中可用,但是自从升级到最新版本(5.x)以来,此异常开始出现。

1 个答案:

答案 0 :(得分:2)

  

有点困惑,它曾经在NH 2.x中工作,

与此pull request一起在5.2中确实更改了unsaved-value的处理。 如果我正确理解此PR,则可以解决某些情况,其中忽略了为分配的标识符提供的unsaved-value映射。

因此,对于具有已分配标识符的实体,您似乎有错误的unsaved-value映射。从给定的数据尚不清楚您期望NHibernate如何确定实体是否是瞬态的。在您的映射中,如果Id不等于Guid.Empty,NHibernate将为所有级联实体触发UPDATE语句,看来这是确切的行为。 如果要让它在会话中不存在实体时检查数据库,请将其设置为"undefined"

Id(x => x.Id).GeneratedBy.GuidComb().UnsavedValue("undefined");

如果您希望它始终保存实体,请将其设置为"any"

阅读spec并附上所有其他可能值的说明。还要检查类似的issue