流畅的NHibernate一对多映射

时间:2012-06-01 16:12:54

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

我有以下两个班级:

广告

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

AdvertImage

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

在数据库中,我的AdvertImages表格中有FK'AddidId',它与广告表中的PK为'Id'有关。

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

My Fluent NHibernate映射(为简洁起见编辑)是:

AdvertMap

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

AdvertImageMap

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

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

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

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

3 个答案:

答案 0 :(得分:10)

您需要将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();
    }
}

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

public class Advert
{
    public virtual IList<AdvertImage> AdvertImages { get; set; }

    public virtual void AddImage(AdvertImage newImage)
    {
        newImage.Advert = this;
        AdvertImages.Add(newImage);
    }
}

答案 1 :(得分:2)

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

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

答案 2 :(得分:1)

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

以下是一些可能有用的类似问题:Cascade insert on one-to-many with fluent NHibernate