2009-11-27 87 views
0

我有两个相关的对象:ProgramSession和ProgramTask,具有一对多的关系。一个ProgramSession有许多ProgramTasks。所以物体看起来是这样的:NHibernate:父列表属性和相关的子属性不同步

public class ProgramSession 
{ 
    public virtual IList<ProgramTask> ProgramTasks 
    { 
     get { return _programTasks; } 
     set { _programTasks = value; } 
    } 
} 

public class ProgramTask 
{ 
    public virtual ProgramSession ProgramSession 
    { 
     get { return _programSession; } 
     set { _programSession = value; } 
    } 
} 

而且映射...

ProgramSession.hbm.xml

<bag name="ProgramTasks" lazy="false" cascade="all-delete-orphan" inverse="true" > 
    <key column="SessionUid"></key> 
    <one-to-many class="ProgramTask"></one-to-many> 
</bag> 

ProgramTask.hbm.xml

<many-to-one name="ProgramSession" column="SessionUid" class="ProgramSession" /> 

的问题当我尝试更改ProgramTask的ProgramSession时开始。

如果我从旧会话的ProgramSession.ProgramTasks列表属性中删除ProgramTask,然后将其添加到新会话的相同属性,NHibernate告诉我已删除的对象将被重新保存。

如果我只是改变ProgramTask.ProgramSession对象的值,我没有问题保存。但是,如果我不立即保存,我会得到奇怪的行为,因为ProgramSession.ProgramTasks属性(在两个会话上)只有在NHibernate会话刷新后才会同步。

更改ProgramTask.ProgramSession对象而不直接修改列表也会创建无效状态。以下面的代码作为示例:

programTask.ProgramSession = newProgramSession; 
Assert.That(newProgramSession.ProgramTasks.Contains(programTask)); // fails 
Assert.That(!oldProgramSession.ProgramTasks.Contains(programTask)); // fails 

这是在代码在被执行以后,它假定集合与ProgramSession属性同步的ProgramTasks更成问题。例如:

foreach(var programTask in programSession.ProgramTasks) 
{ 
    // whatever 
} 

我用来解决这个问题的一个窍门是查询列表。我不能在任何地方使用它,它显然是一个坏的解决方案,但它强调了这个问题:

var tasksActuallyInSession = 
    programSession.ProgramTasks 
     .Where(task => task.ProgramSession == programSession) 
     .ToList(); 

有什么办法来处理这种情况?最佳做法?难道我做错了什么?映射不正确?是否有一些我需要设置的超级秘密NHibernate标志?

+0

我相信你的意思是把这些属性放在你在问题中定义的类中。 – tolism7 2009-11-27 14:43:24

+0

你说得对。感谢您的高举。 – shovavnik 2009-11-27 15:03:42

回答

1

不知道我是否理解你在这里所做的一切。一些想法:

如果你决定移动ProgramTasks左右,那么他们是独立的,不应该使用cascade="all-delete-orphan"映射。如果你这样做,当你从ProgramSession中删除它时,NH从数据库中删除ProgramTask

使用cascade="none"映射它并自己控制对象的生命周期。 (这意味着:在ProgramSession存储之前将其存储,当它不再使用时将其删除)

不确定这是否也是问题,但请注意,如果您有反向引用,则您的代码负责使参考文献保持一致。当然,在存储到数据库并加载到空会话后,引用会被清理干净,这是因为数据库中只有一个外键。但这不是它应该完成的方式。 NH不负责管理您的参考。 (它唯一的责任是坚持你在记忆中正在做的事情。)所以你需要在内存中保持一致,并且实现你的业务逻辑,就好像没有NHibernate一样。

+0

级联选项的伎俩。我做了一些更多的研究,并在某些关系上解决了级联=“删除”。这种方法的一个警告是我现在需要跟踪哪些实体是新的,以便我可以决定是否在实体上调用Save()或Update(),而在我使用SaveOrUpdate()之前。所以这实际上加深了我对NHibernate的依赖,但它的工作原理。谢谢。 – shovavnik 2009-11-30 15:41:00