流畅的休眠映射,可双向保存

Posted

技术标签:

【中文标题】流畅的休眠映射,可双向保存【英文标题】:fluent nhibernate mappings that save in both directions 【发布时间】:2015-07-09 20:23:04 【问题描述】:

我希望能够做到以下几点:

var child = new Child 
  Name = "foo",
  Parent = new Parent  Name = "bar" 
;

session.Save(child);

var parent = new Parent 
  Name = "foo",
  Children = new List<Child> 
    new Child  Name = "bar" ,
    new Child  Name = "baz" ,
  ,
;

session.Save(parent);

当调用Save() 时,在这两种情况下都保存所有创建的对象。这是课程。我不知道如何映射ParentChild 之间的一对多关系,这将有助于在一次调用Save() 中保存所有创建的对象。我希望任何一个版本都可以使用,但在任何给定时间只会使用一个。这背后的基本原理是我正在创建测试数据构建器,在某些情况下,从Child 端连接起来会更容易,而在其他情况下,从Parent 端连接起来会更容易。因此,为什么我希望能够在给定任一对象的情况下在两个方向上级联插入和删除。我不关心更新。这只会用于插入数据、针对应用运行我的测试,然后删除数据。

以下是涉及的类:

public class Child 
  public virtual int Id  get; set; 
  public virtual string Name  get; set; 
  public virtual Parent Parent  get; set; 


public class Parent 
  public virtual int Id  get; set; 
  public virtual string Name  get; set; 
  public virtual IEnumerable<Child> Children  get; set; 


public ChildMap : ClassMap<Child> 
  public ChildMap() 
    Id(x => x.Id);
    Map(x => x.Name);

    // How should I set this up?
    Reference(x => x.Parent);
  


public ParentMap : ClassMap<Parent> 
  public ParentMap() 
    Id(x => x.Id);
    Map(x => x.Name);

    // How should I set this up ?
    HasMany(x => x.Children);
  

【问题讨论】:

最好将 Children 集合设为只读并使用初始化语法:new Parent Children = new Child Name = "bar" , new Child Name = "baz" , ; @Firo 你能把它变成一个完整的答案吗? 最好的做法是这样做(尤其是使用 ORM),但它不能回答问题。 IMO Radim Köhler 给出了一个很好且完整的答案。 【参考方案1】:

为了能够从两边保存级联,我们可以使用级联设置

所以,这个映射就足够了:

public ChildMap() 

    ...
    BatchSize(100);  // this is the way how to solve 1 + N (good practice, mine at least)

    // How should I set this up?
    References(x => x.Parent) // References, not Reference
        .Cascade.SaveUpdate()
        ;


public ParentMap() 

    ...
    BatchSize(100);  // this is the way how to solve 1 + N

    // How should I set this up ?
    HasMany(x => x.Children)
       .BatchSize(100)  // no 1 + N
       .Cascade.AllDeleteOrphan()
       .Inverse()
       ;

通过这些设置,上述设置将起作用,但有一个重要更改 - 子级必须了解其父级。因为我们使用逆...

这将起作用:

var child = new Child

    Name = "foo",
    Parent = new Parent Name = "bar"
;

session.Save(child);
session.Flush();
session.Clear();

var persistedChild = session.Get<Child>(child.ID);

这也是如此(但要设置 child.Parent 参考)

var parent = new Parent

    Name = "foo",
    Children = new List<Child>
    
        new Child Name = "bar",
        new Child Name = "baz",
    ,
;

foreach (var ch in parent.Children)

    ch.Parent = parent; // we MUST do this, there is .Inverse()


session.Save(parent);
session.Flush();
session.Clear();

var persistedParent = session.Get<Parent>(parent.ID);

阅读more here 了解batch size(不是问题的一部分,但我总是使用它)

关于逆映射和reference assignment的其他一些细节

还有,为什么我们不能在 .Rferences() 上使用相同的级联(多对一)NHibernate Many-to-one cascade

【讨论】:

以上是关于流畅的休眠映射,可双向保存的主要内容,如果未能解决你的问题,请参考以下文章

流畅的nhibernate父子映射

流畅的 nHibernate 映射问题

流畅的python和cookbook学习笔记

流畅的 NHibernate HASMANY 映射,无需参考

IList<int> 的流畅 NHibernate 映射?

《流畅的python》学习笔记及书评