NHibernate 3.x 在组合 LINQ 分页、多对多和子选择获取时删除子实体
我们的应用程序具有故事的概念和标签的概念。一个故事可以应用多个标签,一个标签也可以应用到多个故事,从而形成多对多的关系。 Stories 和 Tags 这两个表与第三个表 StoriesToTags 桥接。
映射文件的相关部分如下:
这是从 Story 到 Tag 的映射:
<class name="Story" table="Stories">
...
<set fetch="subselect" name="Tags" table="StoriesToTags">
<key>
<column name="StoryId" />
</key>
<many-to-many class="Tag">
<column name="TagId" />
</many-to-many>
</set>
</class>
以及从 Tag 到 的逆关系故事:
<class name="Tag" table="Tags">
...
<set fetch="subselect" inverse="true" name="Stories" table="StoriesToTags">
<key>
<column name="TagId" />
</key>
<many-to-many class="Story">
<column name="StoryId" />
</many-to-many>
</set>
</class>
如您所见,我们使用子选择获取策略来避免 N+1 查询问题。一切都运行良好,直到您尝试使用 LINQ 对结果进行分页:
IQueryable<Story> stories = GetStories(...).TakePage(pageNumber, pageSize);
运行此查询后,NHibernate 会删除查询中未加载的所有故事的关系(StoriesToTags 中的记录)。它似乎只在专门加载标签时才会发生(即触发子选择)。如果我们切换到join或select获取策略,关系不会被删除,但这会导致执行N+1个查询。
我最好的猜测是 NHibernate 认为标签已被孤立,但我们尚未在集合上设置任何级联。另外,据我所知,设置级联没有任何效果。
这个过程在 NHibernate 2.x 和 NHibernate.Linq 下运行得很好。直到我们迁移到内置 LINQ 支持的 NHibernate 3.x 后,我们才发现删除问题发生。我不确定这会产生什么影响,但就其价值而言,我们正在使用带有身份密钥的 SQL Server。
有什么想法吗?我最初以为我做了一些非常愚蠢的事情,但我基本上尝试了所有映射排列,但我们似乎无法消除这个问题。
编辑:另一个有趣的信息。如果您在关闭会话之前调用 session.IsDirty()
,则不会出现此问题。我怀疑这是因为集合更改在刷新之间不会持久,但我无法很好地破译 NHibernate 的源代码来确定。
Our application has the concept of Stories and the concept of Tags. A story can have many tags applied to it, and a tag can be applied to many stories, making the relationship many-to-many. The two tables, Stories and Tags are bridged with a third, StoriesToTags.
The relevant pieces of the mapping files are as follows:
Here's the mapping from Story to Tag:
<class name="Story" table="Stories">
...
<set fetch="subselect" name="Tags" table="StoriesToTags">
<key>
<column name="StoryId" />
</key>
<many-to-many class="Tag">
<column name="TagId" />
</many-to-many>
</set>
</class>
And the inverse relationship from Tag to Story:
<class name="Tag" table="Tags">
...
<set fetch="subselect" inverse="true" name="Stories" table="StoriesToTags">
<key>
<column name="TagId" />
</key>
<many-to-many class="Story">
<column name="StoryId" />
</many-to-many>
</set>
</class>
As you can see, we're using the subselect fetch strategy to avoid the N+1 query problem. Everything works great, until you attempt to page a result using LINQ:
IQueryable<Story> stories = GetStories(...).TakePage(pageNumber, pageSize);
After running this query, NHibernate deletes the relationships (records in StoriesToTags) for all stories that were not loaded in the query. It only seems to occur when the tags are specifically loaded (that is, the subselect is triggered). The relationships are not deleted if we switch to a join or select fetch strategy, but that causes N+1 queries to be executed.
My best guess is that NHibernate thinks the tags have been orphaned, but we haven't set any cascades on the collections. Also, as far as I can tell, setting a cascade has no effect.
This process worked great under NHibernate 2.x and NHibernate.Linq. We didn't see the issue with deletion occur until we moved to NHibernate 3.x, which has LINQ support built-in. I'm not sure it makes a difference, but for what it's worth, we're using SQL Server with identity keys.
Any thoughts? I initially thought I was doing something insanely stupid, but I've tried basically every permutation of mapping and we can't seem to eliminate the issue.
Edit: Another interesting piece of information. If you call session.IsDirty()
before closing the session, the issue doesn't occur. I suspect that this is because collection changes aren't persisted between flushes, but I can't decipher NHibernate's source well enough to know for certain.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您是否在实体映射中进行了设置: Cascade.None() 这将停止删除除实体之外的任何其他内容。
这可能会有所帮助: http://ayende.com/blog/1890/nhibernate-cascades-the- Different- Between-all-all-delete-orphans-and-save-update
have you set up in mapping of the entity : Cascade.None() this will stop deleting anything else except the entity.
This might help: http://ayende.com/blog/1890/nhibernate-cascades-the-different-between-all-all-delete-orphans-and-save-update
您能给我们一些关于您在这里想要实现的目标的线索吗?我从未尝试过在多对多上进行指定的获取,但我认为这与某种显式级联=多对多的全部有关。
Can you give us some clue at what you are trying to achieve here ? I never experimented with a specified fetch on a many-to-many, but me thinks it got something to do with some sort of explicit cascade= all for a many to many.