Nhibernate OffItem被认为是脏的,它将在保存时保存整个TakeOffItem对象图。如果我真的想保存takefficem,那没关系,但是如果我不想保存takefficem,它会执行很多基本上不必要的查询

Nhibernate OffItem被认为是脏的,它将在保存时保存整个TakeOffItem对象图。如果我真的想保存takefficem,那没关系,但是如果我不想保存takefficem,它会执行很多基本上不必要的查询,nhibernate,Nhibernate,为了解决其中一些问题,我实现了Fabio的代码,该代码将禁用NHibernate中的自动脏检查行为。现在它只保存我调用SaveOrUpdate()的内容(以及级联关系),因此NHibernate认为所有其他对象都是脏的不再重要,因为在刷新会话时它不会保存它们。但现在有些东西被破坏了,因为如果我更改MaterialGroup对象中的集合(例如TakeOffItem.MaterialGroups[0].MaterialGroups.Add(something)),NHibernate没有意识到它需要

为了解决其中一些问题,我实现了Fabio的代码,该代码将禁用NHibernate中的自动脏检查行为。现在它只保存我调用SaveOrUpdate()的内容(以及级联关系),因此NHibernate认为所有其他对象都是脏的不再重要,因为在刷新会话时它不会保存它们。但现在有些东西被破坏了,因为如果我更改MaterialGroup对象中的集合(例如TakeOffItem.MaterialGroups[0].MaterialGroups.Add(something)),NHibernate没有意识到它需要保存这些对象。如果我删除所有自定义加载代码,Fabio的代码就可以正常工作。但出于优化原因,我需要自定义加载代码

我认为部分问题也源于这样一个事实,即我无法告诉NHibernate实体不是脏的(如果有办法,我很想知道!)。我真的希望能够进行自定义加载,然后告诉NHibernate,“嘿,整个对象图都不脏,假装您刚刚加载了它。”


再次感谢您的帮助。

看起来您正在使用CreateSql做一些有趣的事情 我猜您不会从中返回实体。 请发布您正在使用CreateSqlQuery执行的任何操作
你绝对不应该被迫使用session.Lock。我发现了问题所在,但我所做的不是很明显是错的。我想这就是你尝试与NHibernate合作时得到的结果

此代码存在问题:

public override TakeOffItem Get(long id)
{
    var materialGroups = _getMaterialGroupsForTakeOffItemQuery.GetResults(id);

    var fabricationNotesByMaterialDetailsId = _getFabricationNotesForTakeOffItemQuery.GetFabricationNotesForMaterialDetails(
        materialGroups.Where(mg => mg.MaterialDetails != null).Select(mg => mg.MaterialDetails.Id));

    var takeOffItem = base.Get(id);
    _assignMaterialGroupsService.AssignMaterialGroups(id, takeOffItem, materialGroups, fabricationNotesByMaterialDetailsId);
    _session.Lock(takeOffItem, LockMode.None);
    return takeOffItem;
}        
问题是,在加载takefficem(父实体)之前,我正在执行自定义查询。通常,当您使用NHibernate加载内容时,首先加载父对象,会话中已知实体的列表将在子对象之前加载父对象。如果列表中的父实体不在子实体之前,则自动脏检查代码将不起作用,因为它会按顺序遍历已知实体的列表,并将子实体标记为脏实体。如果它试图在父实体之前处理子实体,那么在NHibernate检查是否需要保存它之后,子实体会被标记为脏实体,因此子实体不会被保存

我不知道ISession.Lock()是做什么的,但正如Ayende在回答中所说,我不需要再这样做了。所以我进行了Lock()调用

以下是新代码的外观:

public override TakeOffItem Get(long id)
{
    // Moved this line up
    var takeOffItem = base.Get(id);

    var materialGroups = _getMaterialGroupsForTakeOffItemQuery.GetResults(id);

    var fabricationNotesByMaterialDetailsId = _getFabricationNotesForTakeOffItemQuery.GetFabricationNotesForMaterialDetails(
        materialGroups.Where(mg => mg.MaterialDetails != null).Select(mg => mg.MaterialDetails.Id));

    _assignMaterialGroupsService.AssignMaterialGroups(id, takeOffItem, materialGroups, fabricationNotesByMaterialDetailsId);
    _session.Lock(takeOffItem, LockMode.None);
    return takeOffItem;
}        

这个故事的寓意是:如果您禁用自动脏检行为,并自定义加载实体,请确保在加载子项之前加载父项。

如果您可以发布模式、映射和代码,这将非常有用。
public override TakeOffItem Get(long id)
{
    var materialGroups = _getMaterialGroupsForTakeOffItemQuery.GetResults(id);

    var fabricationNotesByMaterialDetailsId = _getFabricationNotesForTakeOffItemQuery.GetFabricationNotesForMaterialDetails(
        materialGroups.Where(mg => mg.MaterialDetails != null).Select(mg => mg.MaterialDetails.Id));

    var takeOffItem = base.Get(id);
    _assignMaterialGroupsService.AssignMaterialGroups(id, takeOffItem, materialGroups, fabricationNotesByMaterialDetailsId);
    _session.Lock(takeOffItem, LockMode.None);
    return takeOffItem;
}        
public override TakeOffItem Get(long id)
{
    // Moved this line up
    var takeOffItem = base.Get(id);

    var materialGroups = _getMaterialGroupsForTakeOffItemQuery.GetResults(id);

    var fabricationNotesByMaterialDetailsId = _getFabricationNotesForTakeOffItemQuery.GetFabricationNotesForMaterialDetails(
        materialGroups.Where(mg => mg.MaterialDetails != null).Select(mg => mg.MaterialDetails.Id));

    _assignMaterialGroupsService.AssignMaterialGroups(id, takeOffItem, materialGroups, fabricationNotesByMaterialDetailsId);
    _session.Lock(takeOffItem, LockMode.None);
    return takeOffItem;
}