【问题标题】:Fluent NHibernate One-To-Many MappingFluent NHibernate 一对多映射
【发布时间】:2012-06-01 16:12:54
【问题描述】:

我有以下两个课程:

广告

public virtual int Id { get; set;
public virtual IList<AdvertImage> AdvertImages { get; set; }

广告图片

public virtual int Id { get; set; }
public virtual string Filename { get; set;
public virtual Advert Advert { get; set; }

在数据库中,我的 AdvertImages 表具有 FK 'AdvertId',它与具有 'Id' 的 PK 的 Adverts 表相关。

这是一对多的映射,因为一个广告可以有许多图像。

我的 Fluent NHibernate 映射(为简洁而编辑)是:

广告地图

Id(x => x.Id)
  .GeneratedBy.Identity();
...
HasMany(x => x.AdvertImages)
  .KeyColumn("AdvertId")
  .Inverse();
...
Table("Adverts");

广告图片地图

Id(x => x.Id)
  .GeneratedBy.Identity();
...
References(x => x.Advert)
  .Column("AdvertId");
...
Table("AdvertImages");

我正在代码中创建Advert 的新实例,然后用List&lt;AdvertImage&gt; 填充(广告的)AdvertImages 属性。

当我将我的Advert 对象持久化到数据库时,我希望将 AdvertImages 插入到他们的 AdvertImages 表中,但由于这两个表之间的关系,我需要先插入 Advert,所以在生成 PK Id 时,可以将其插入 AdvertImages 表中。 (当我创建 AdvertImage 列表时,我正在填充 Filename 属性,但显然在那个阶段没有新的 AdvertId,因此希望在将广告持久保存到数据库时填充它。

我尝试了不同的 Inverse() 和 Cascade 设置,但还没有成功。有人可以帮忙吗?

【问题讨论】:

    标签: nhibernate fluent-nhibernate nhibernate-mapping fluent-nhibernate-mapping


    【解决方案1】:

    您需要将Advert 映射更改为级联:

    Id(x => x.Id)
      .GeneratedBy.Identity();
    
    HasMany(x => x.AdvertImages)
      .KeyColumn("AdvertId")
      .Inverse()
      .Cascade.AllDeleteOrphan();
    
    Table("Adverts");
    

    然后你应该能够做这样的事情来持久化一个 Advert 对象和它的孩子 AdvertImage

    Advert newAdvert = new Advert();
    AdvertImage newImage = new AdvertImage();
    newImage.Advert = newAdvert;
    newAdvert.AdvertImages.Add(newImage);
    
    using(NHibernate.ISession session = SessionFactory.GetCurrentSession())
    {
        using (NHibernate.ITransaction tran = session.BeginTransaction())
        {
            session.Save(newAdvert);
            tran.Commit();
        }
    }
    

    我的实体通常包含双向一对多关系的 Add 和 Remove 方法,如下所示:

    public class Advert
    {
        public virtual IList<AdvertImage> AdvertImages { get; set; }
    
        public virtual void AddImage(AdvertImage newImage)
        {
            newImage.Advert = this;
            AdvertImages.Add(newImage);
        }
    }
    

    【讨论】:

    • 感谢 Cole W,以及关于添加和删除方法的好提示。
    【解决方案2】:

    我遇到了同样的问题。我花了一段时间尝试所有不同类型的映射。然后我发现我的映射很好,实际上我需要将会话包装在事务中并在 session.SaveOrUpdate() 方法之后使用 Commit() 方法。

    using(var session = sessionFactory.OpenSession()) 
    using(var tx = session.BeginTransaction()) 
    { 
    // execute code that uses the session 
    tx.Commit(); 
    }
    

    【讨论】:

    • 感谢 .. 节省了大量时间来解决这个问题
    【解决方案3】:

    通常对我有用的是设置外键列以允许 DB 中的空值 - 这将是您的 AdvertId 列,但我不确定这是否适用于您的情况,因为您使用的是身份。 NHibernate 所做的是用一个查询插入所有内容,然后将子表外键列更新为父表的正确 id。也许它也适用于您的情况。

    这里有一些类似的问题可能会有所帮助:Cascade insert on one-to-many with fluent NHibernate

    【讨论】:

    • 你包含的那个链接没有意义,因为它与Fluent NHibernate无关。
    • @KomengeMwandila 虽然我链接的问题的答案不使用 Fluent NHibernate,但问题确实如此。此外,Fluent NHibernate 并没有在这里添加任何新内容。它只是为 NHibernate 映射提供了另一个接口。一旦了解了映射的工作原理,就可以将其应用到 Fluent NHibernate、XML 映射、代码映射...
    猜你喜欢
    • 2011-01-29
    • 1970-01-01
    • 2011-07-17
    • 1970-01-01
    • 2010-12-07
    • 1970-01-01
    • 2012-02-24
    • 1970-01-01
    相关资源
    最近更新 更多