NHibernate 3.x在组合LINQ分页,多对多和子选择提取时删除子实体

时间:2011-05-24 14:57:20

标签: linq nhibernate linq-to-nhibernate

我们的应用程序具有故事的概念和标签的概念。故事可以应用许多标签,标签可以应用于许多故事,使关系多对多。两个表格 Stories 标签与第三个 StoriesToTags 进行桥接。

映射文件的相关部分如下:

以下是从故事标记的映射:

<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>

标记故事的反向关系:

<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>

如您所见,我们正在使用 subselect 获取策略来避免N + 1查询问题。一切都很好,直到您尝试使用LINQ:

来分页结果
IQueryable<Story> stories = GetStories(...).TakePage(pageNumber, pageSize);

运行此查询后,NHibernate会删除未在查询中加载的所有故事的关系( StoriesToTags 中的记录)。它似乎只在标记被特定加载时发生(即,触发子选择)。如果我们切换到 join 选择获取策略,则不会删除关系,但这会导致执行N + 1个查询。

我最好的猜测是NHibernate认为标签已经成为孤儿,但我们没有在集合上设置任何级联。另外,据我所知,设置级联没有效果。

这个过程在NHibernate 2.x和NHibernate.Linq下运行良好。在我们转移到内置LINQ支持的NHibernate 3.x之前,我们没有看到删除问题。我不确定它有什么不同,但是对于它的价值,我们使用带有身份密钥的SQL Server。

有什么想法?我最初认为我做的事情非常愚蠢,但我基本上尝试了映射的每一种排列,我们似乎无法消除这个问题。

编辑:另一条有趣的信息。如果在关闭会话之前致电session.IsDirty(),则不会发生此问题。我怀疑这是因为在刷新之间不会持续收集更改,但是我无法解释NHibernate的源代码以确定无疑。

2 个答案:

答案 0 :(得分:1)

你设置了实体的映射:Cascade.None()这将停止删除除实体之外的任何其他内容。

这可能会有所帮助:http://ayende.com/blog/1890/nhibernate-cascades-the-different-between-all-all-delete-orphans-and-save-update

答案 1 :(得分:0)

你能告诉我们你在这里想要达到的目标吗?我从来没有尝试过多对多的指定抓取,但我认为它与某种显式级联有关 - =对于多对多都是如此。