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



我们的应用程序具有StoriesTags的概念。一个故事可以应用许多标签,一个标签可以应用于许多故事,从而形成多对多的关系。故事标签这两个表与第三个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中的记录)。它似乎只在特定加载标签时发生(即触发子选择)。如果我们切换到联接选择提取策略,则不会删除关系,但这会导致执行N+1查询。

我的最佳猜测是,NHibernate认为这些标签已经成为孤儿,但我们还没有对这些集合设置任何级联。此外,据我所知,设置级联没有任何效果。

这个过程在NHibernate 2.x和NHibernate.Linq下运行得很好。直到我们转到内置Linq支持的NHibernat 3.x,我们才发现删除问题。我不确定它有什么不同,但就其价值而言,我们使用的是带有标识密钥的SQL Server。

有什么想法吗?起初我觉得我在做一些愚蠢至极的事情,但我基本上尝试了映射的每一种排列,但我们似乎无法消除这个问题。

编辑:另一条有趣的信息。如果在关闭会话之前调用session.IsDirty(),则不会出现问题。我怀疑这是因为在刷新之间收集的更改没有持续存在,但我无法很好地破译NHibernate的来源,无法确定。

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

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

你能给我们一些线索吗?我从未尝试过对多对多进行特定的提取,但我认为这与某种显式级联有关。

相关内容

  • 没有找到相关文章

最新更新