简体   繁体   English

从NHibernate中的子级联创建时,如何获得新的父级ID?

[英]How do I get a new parent ID when cascade creating from a child in NHibernate?

I have a parent child relationship where the parent doesn't have a reference to the children - something like this : 我有一个父子关系,父母没有对孩子的引用-像这样:

class Child
{
    int Id { get; set;
    Parent Parent { get; set; }
    // + other stuff
}

class Parent
{
    int Id { get; set; }
    // + other stuff
}

In the database this just means that the Child table has a ParentID column. 在数据库中,这仅意味着Child表具有ParentID列。 This column can be null - ie it's possible to have a Parent -less Child . 该列可以为空-即可以有一个没有Parent Child

I'm using Fluent conventions to map the domain, but there's an override for this relationship so that we can update a Child and create a new Parent at the same time : 我正在使用Fluent约定来映射域,但是对此关系有一个替代,以便我们可以同时更新Child并创建新的Parent

public class ChildOverride : IAutoMappingOverride<Child>
{
    public void Override(AutoMapping<Child> mapping)
    {
        mapping.References(x => x.Parent).Cascade.All();
    }
}

The problem arises when we add a new Parent to an existing Child and immediately need to read the ID of that Parent (while in a transaction), eg : 当我们向现有Child添加新的Parent并且立即需要(在交易中)读取该父代的ID时,就会出现问题,例如:

existingChild.CreateParent(parameters);
session.Save(existingChild);
Debug.WriteLine(existingChild.Parent.Id);

Which just prints 0 rather than giving me the Id of the new Parent - I had assumed Cascade.All() would...well, cascade. 它只是打印0而不是给我新的Parent的Cascade.All()我假设Cascade.All()会...好吧,级联。 Is that wrong? 错了吗

If I commit the transaction before accessing the Id, everything is fine, or if I save the new Parent explicitly that works too, eg 如果我在访问ID之前提交了事务,那么一切都很好,或者如果我也明确保存了新父类也可以工作,例如

// This works
existingChild.CreateParent(parameters);
session.Save(existingChild);
transaction.Commit();
Debug.WriteLine(existingChild.Parent.Id);

// This also works
existingChild.CreateParent(parameters);
session.Save(existingChild);
session.Save(existingChild.Parent);
Debug.WriteLine(existingChild.Parent.Id);

Is there any way I can change my override so that saving the child object will allow the parent id to be immediately accessible? 有什么方法可以更改覆盖,以便保存子对象将允许立即访问父ID? (Or is there something else I'm doing wrong?) (或者我做错了什么吗?)

The good is, that all is working properly . 这样做的好处是, 所有人都在正常工作 And your mapping is correct . 而且您的映射是正确的 Because if this snippet is working... 因为如果该代码段有效...

// This works
existingChild.CreateParent(parameters);
session.Save(existingChild);
transaction.Commit();

... the concept is working as well. ...这个概念也行得通。 Why? 为什么? What is all about? 到底是什么? Why Commit() helped to solve that? 为什么Commit()可以解决这个问题?

Well, because ISession is an abstraction , it is the virtual persistence storage. 好吧,因为ISession是一个抽象 ,所以它是虚拟的持久性存储。 It does not execute any SQL Statements in the moment we call session.Save() . 在我们调用session.Save()的那一刻,它执行任何SQL语句。 It just keeps all information (gathered during working with that session) and executing the SQL WRITE Statements only 它仅保留所有信息(在该会话期间收集)并仅执行SQL WRITE语句

  • if desperately must (the ID generated by DB is needed for farther stuff) 是否必须(由DB生成的ID用于其他操作)
  • if the session decides (if allowed ... see below session mode Auto) 如果会话决定(如果允许,请参见下面的会话模式自动)
  • if explicitly asked for 如果明确要求

But better and more precise will be to cite doc: 但是更好更精确的是引用doc:

9.6. 9.6。 Flush 冲洗

From time to time the ISession will execute the SQL statements needed to synchronize the ADO.NET connection's state with the state of objects held in memory. ISession会不时执行将ADO.NET连接状态与内存中保存的对象状态同步所需的SQL语句。 This process, flush, occurs by default at the following points 默认情况下,此过程在以下几点进行刷新

... ...

Except when you explicity Flush() , there are absolutely no guarantees about when the Session executes the ADO.NET calls , only the order in which they are executed. 除了显式地使用Flush()绝对不能保证Session何时执行ADO.NET调用 ,只能保证它们执行的顺序。 However, NHibernate does guarantee that the ISession.Find(..) methods will never return stale data; 但是,NHibernate确实保证了ISession.Find(..)方法将永远不会返回过时的数据。 nor will they return the wrong data. 他们也不会返回错误的数据。

It is possible to change the default behavior so that flush occurs less frequently. 可以更改默认行为,以便减少刷新的频率。 The FlushMode class defines three different modes: only flush at commit time (and only when the NHibernate ITransaction API is used), flush automatically using the explained routine (will only work inside an explicit NHibernate ITransaction), or never flush unless Flush() is called explicitly. FlushMode类定义了三种不同的模式:仅在提交时进行刷新(并且仅在使用NHibernate ITransaction API时);使用说明的例程自动进行刷新(仅在显式的NHibernate ITransaction中起作用);或者除非Flush()为显式调用。 The last mode is useful for long running units of work, where an ISession is kept open and disconnected for a long time (see Section 11.4, “Optimistic concurrency control”). 最后一种模式对于长时间运行的工作单元很有用,在这种情况下,ISession长时间保持打开和断开状态(请参见第11.4节“乐观的并发控制”)。

And there is the answer. 并且有答案。 The FlushMode setting: FlushMode设置:

public enum FlushMode
{
    Unspecified = -1,
    Never = 0,
    Commit = 5,
    Auto = 10,
    Always = 20,
}

So, if the FlushMode is Commit - only transaction commit triggers the session.Flush() 因此,如果FlushMode为Commit只有事务提交才触发session.Flush()

But we can do it any time ourselves: 但是我们可以随时自己做:

// This works
existingChild.CreateParent(parameters);
session.Save(existingChild);
session.Flush();

And now parent will have the ID - becuase session state was just converted into SQL WRITE operations... 现在父级将具有ID-因为会话状态刚刚转换为SQL WRITE操作...

You are using a ID generation strategy that only generates the ID when the object hits the DB. 您正在使用ID生成策略,该策略仅在对象命中数据库时才生成ID。 If you want to have parent ID before that, you'll need to take the ID generation into your hand, using assigned strategy. 如果您希望在此之前拥有父ID,则需要使用assigned策略将ID生成交给您。

It's a long topic that I don't want to repeat here. 这个话题很长,我不想在这里重复。 You can read about what you need to do here: Don't Let Hibernate Steal Your Identity 您可以在这里阅读有关您需要做的事情: 不要让休眠状态窃取您的身份

In the article, the ID type is UUID. 在本文中,ID类型为UUID。 You can easily implement a custom ID generator for int or long data types. 您可以轻松地为intlong数据类型实现自定义ID生成器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用NHibernate从父ID获取孩子 - Get child from parent id using NHibernate 创建子对象时如何从子对象内的父对象获取ID? (MVC) - How to get ID from parent object inside child object when creating it? (MVC) 在NHibernate中通过ID或父对象获取子对象? - Get child objects by id or parent object in NHibernate? 流利的具有自动映射功能的nHibernate:如何从子级获取父级或“污染”对象 - Fluent nHibernate with Automapping: How to get a parent or “containg” object from a child NHibernate Composite-ID子级联异常 - Exception NHibernate Composite-ID Child Cascade Fluent NHibernate - 当模型中不存在明确的parent-&gt; child关系时,Cascade删除子对象 - Fluent NHibernate - Cascade delete a child object when no explicit parent->child relationship exists in the model nHibernate:在创建子对象时保存新的父对象 - nHibernate: Saving new parent object while creating a child object 我如何从孩子那里获得父母收藏的计数? - How do I get Count of parent collection from child? NHibernate-保存父级时,层叠级保存-更新时是否应更新所有子对象? - NHibernate - Should all child objects be updated when parent is saved, when cascade is save-update? NHibernate - 按父ID选择子项 - NHibernate - select child by parent id
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM