如何添加映射为新的对象为IList一个一对多与NHibernate?(How to add new

2019-07-31 19:09发布

我的模型包含一个类Section ,其具有的有序列表Statics是本节的一部分。 离开所有其他属性了,该模型的实现看起来是这样的:

public class Section
{
    public virtual int Id { get; private set; }
    public virtual IList<Static> Statics { get; private set; }
}

public class Static
{
    public virtual int Id { get; private set; }
}

在数据库中,关系实现为一个一对多,其中表Static有一个外键指向Section和一个整数列Position存储在列表中它的一部分,其索引位置。

映射在功能NHibernate做过这样的:

public SectionMap()
{
    Id(x => x.Id);
    HasMany(x => x.Statics).Cascade.All().LazyLoad()
            .AsList(x => x.WithColumn("Position"));
}

public StaticMap()
{
    Id(x => x.Id);
    References(x => x.Section);
}

现在我能够加载现有的Static s,而我也能更新这些细节。 不过,我似乎无法找到一个方法来添加新的Static s到一个Section ,而此改变保存到数据库。 我曾尝试的几种组合:

  • mySection.Statics.Add(myStatic)
  • session.Update(mySection)
  • session.Save(myStatic)

但我得到的最接近(使用前两个语句),是一个SQL异常读数:“无法将NULL值插入列‘位置’”。 显然,一个INSERT这里尝试,但NHibernate的似乎并没有自动追加索引位置的SQL语句。

我究竟做错了什么? 我失去了我的映射的东西吗? 我需要暴露Position列属性和值分配给它自己?

编辑:显然,一切正常,如果我删除NOT NULL的约束Static.Position的数据库列。 我想NHibernate的使得插入和更新立刻用行后Position值。

虽然这是一个anwers的问题,我不知道这是否是最好的之一。 我宁愿Position列是不可空的,所以我还是希望有一些方法,使NHibernate的提供直接在列中的值INSERT语句。

因此,这个问题仍然是开放的。 任何其他解决办法?

Answer 1:

当使用NHibernate的双向一个一对多关系的端部中的一个必须是“逆”。 最佳做法是设定与集合作为​​逆结束,因为这避免了不必要的SQL语句,并允许ID列是“不空”。

在6.4节的文档,你可以找到下面的注释:

非常重要的注意事项:如果一个协会的列声明NOT NULL,NHibernate的可能导致违反约束时,它会创建或更新关联。 为了避免这个问题,你必须使用双向关联,用标记为逆=“真”的许多有价值的一端(套或袋)。 请参阅本章后面关于双向关联的讨论。

所以,你需要.Inverse()添加到您的SectionMap映射的hasMany。

public SectionMap()
{
    Id(x => x.Id);
    HasMany(x => x.Statics)
        .Cascade.All()
        .LazyLoad()
        .Inverse()
        .AsList(x => x.WithColumn("Position"));
}

你也可能会想要一个添加和科,该科将删除方法/重置静态的参考以及添加/从自己收藏的去除静态到/:

public virtual void AddStatic(Static static)
{
    Statics.Add(static);
    static.Section = this;
}


public virtual void RemoveStatic(Static static)
{
    Statics.Remove(static);
    static.Section = null;
}

这些方法可以确保引用保持准确的关系的双方。

根据第6.8节的文档使用索引集合时NHibernate的不支持双向关系:

请注意,NHibernate的不支持双向one-to-many关联与索引的集合(列表,地图或数组)作为“多”端,你必须使用一组或包映射。

所以,如果你仍然有问题,可以考虑使用一个单向的关系,而不是双向的,但是这可能意味着你的外键列需要可空(根据在文章的开头的说明)。 否则,你可能需要您的收藏地图袋或集而不是一个列表。



Answer 2:

在静态的表,你有一个名为“SectionID”或类似的东西领域。 让本场可为空:NHibernate的第一添加新的记录,然后更新所引用的ID。

我发现,在我的数据库,我也感到惊讶:为什么NH不喜欢在数据库级别适当表引用?



Answer 3:

我想我会在我的0.02 $扔,只是因为我来到这里寻找解决你的问题,它似乎没有答案的实际工作。

你几乎没有在您的解决方案。 您的的hasMany映射是正确的。 问题是,正如你所说的,位置没有在数据库中保存更新(FWIW,当你将它设置为null,它只是“工作”,因为NULL被插入到数据库;在我看来,这不是真正的工作;) )。

我觉得有点奇怪,你需要地图上的静态类的位置也是如此,明明包括静态一个位置属性。 你不想要的位置属性是可写的,但因为它的价值是由其中的静态在列表中确定。

以下内容添加到静态

public virtual int Position 
{
    get 
    {
        // Will throw exception if Section is null
        // or Section.Statics is null...
        return Section.Statics.IndexOf(this);
    }
    protected set 
    {
    }
}

与在数据库中的地位列将被更新(记得把你的映射在你StaticMap位置)。

我猜静态的NHib代理可以更新位置字段取决于在清单中的位置(由一些魔术大于我拥有),并随后被保存到数据库。



文章来源: How to add new object to an IList mapped as a one-to-many with NHibernate?