如何将新对象添加到映射为NHibernate的一对多的IList? [英] How to add new object to an IList mapped as a one-to-many with NHibernate?

查看:167
本文介绍了如何将新对象添加到映射为NHibernate的一对多的IList?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的模型包含一个类部分,它有一个有序列表 Statics ,它们是本节的一部分。留下所有其他的属性,模型的实现如下所示:

  public class Section 
{
public virtual int Id {get;私人设置}
公共虚拟IList< Static>静态{get;私人设置}
}

public class Static
{
public virtual int Id {get;私人设置}





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



映射在Fluent NHibernate中是这样完成的:

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

$ b $ public staticMap()
{
Id(x => x.Id);
参考文献(x => x.Section);



$ b现在我可以加载现有的 Static
code> s,我也能够更新这些细节。但是,我似乎无法找到一种方法来添加新的静态 s到一个部分,并且这个变化持续到数据库。我尝试了几种组合:




  • mySection.Statics.Add(myStatic)

  • session.Update(mySection)

  • session.Save (myStatic)



但是最接近的(使用前两个语句) SQL异常读取:不能将值NULL插入列'位置'。很明显,在这里尝试了一个 INSERT ,但是NHibernate似乎没有自动将索引位置附加到SQL语句中。



我在做什么错了?我在映射中丢失了什么吗?我是否需要将 Position 列作为一个属性公开并为其分配一个值?

编辑:显然,如果我删除 Static.Position 上的 NOT NULL 约束,数据库中的列。我猜NHibernate使插入和立即更新行后有一个位置价值。



虽然这是anwers对于这个问题,我不确定这是否是最好的。我更喜欢 Position 列不能为空,所以我仍然希望有一些方法可以让NHibernate直接在 INSERT 语句。



因此,问题仍然是开放的。任何其他的解决方案?解决方案在NHibernate中使用双向一对多关系时,其中一个端点必须是反向的 。最佳做法是将集合的结尾设置为反向,因为这样可以避免不必要的SQL语句,并允许id列为not null。

第6.4节的文档可以找到以下注意事项: / b>


非常重要注意:如果关联的列被声明为NOT NULL,那么当NHibernate创建或更新关联时可能会导致违反约束。为了防止这个问题,您必须使用与被标记为inverse =true的许多有价值的结尾(集合或行李)的双向关联。请参阅本章后面的双向关联的讨论。


$ b因此,你需要在。 $ b

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





$你也可能需要一个Section的Add和Remove方法,重置静态的引用以及向自己的集合中添加/删除静态:

preublic $ public void AddStatic(静态静态)
{
Statics.Add(static);
static.Section = this;


$ b public virtual void RemoveStatic(静态静态)
{
Statics.Remove(static);
static.Section = null;





这些方法确保了关系两边的引用保持准确。

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


请注意,NHibernate不支持不支持与索引集合(列表,地图或数组)的双向一对多关联作为多端,您必须使用集合或包映射。因此,如果您仍然遇到麻烦,请考虑使用单向关系而不是双向关系,但这可能意味着您的外键列需要可以为空(根据帖子开头的注释)。否则,您可能必须将您的收藏集作为包或集而不是列表映射。


My model contains a class Section which has an ordered list of Statics that are part of this section. Leaving all the other properties out, the implementation of the model looks like this:

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; }
}

In the database, the relationship is implemented as a one-to-many, where the table Static has a foreign key pointing to Section and an integer column Position to store its index position in the list it is part of.

The mapping is done in Fluent NHibernate like this:

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);
}

Now I am able to load existing Statics, and I am also able to update the details of those. However, I cannot seem to find a way to add new Statics to a Section, and have this change persisted to the database. I have tried several combinations of:

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

but the closest I have gotten (using the first two statements), is to an SQL exception reading: "Cannot insert the value NULL into column 'Position'". Clearly an INSERT is attempted here, but NHibernate does not seem to automatically append the index position to the SQL statement.

What am I doing wrong? Am I missing something in my mappings? Do I need to expose the Position column as a property and assign a value to it myself?

EDIT: Apparently everything works as expected, if I remove the NOT NULL constraint on the Static.Position column in the database. I guess NHibernate makes the insert and immediatly after updates the row with a Position value.

While this is an anwers to the question, I am not sure if it is the best one. I would prefer the Position column to be not nullable, so I still hope there is some way to make NHibernate provide a value for that column directly in the INSERT statement.

Thus, the question is still open. Any other solutions?

解决方案

When using a bidirectional one-to-many relationship in NHibernate one of the ends must be "inverse". Best practice is to set the end with the collection as inverse, since that avoids unnecessary SQL statements and allows the id column to be "not null".

In section 6.4 of the documentation you can find the following note:

Very Important Note: If the column of a association is declared NOT NULL, NHibernate may cause constraint violations when it creates or updates the association. To prevent this problem, you must use a bidirectional association with the many valued end (the set or bag) marked as inverse="true". See the discussion of bidirectional associations later in this chapter.

So, you need to add .Inverse() to your HasMany mapping in SectionMap.

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

You would also probably want an Add and Remove method on Section, which sets/resets the reference of the static as well as adding/removing the static to/from its own collection:

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


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

These methods makes sure the references are kept accurate on both sides of the relationship.

According to section 6.8 of the docs NHibernate does not support bidirectional relationships when using indexed collections:

Please note that NHibernate does not support bidirectional one-to-many associations with an indexed collection (list, map or array) as the "many" end, you have to use a set or bag mapping.

So, if you are still having trouble, consider using a unidirectional relationship instead of a bidirectional, however that might mean that your foreign key column needs to be nullable (according to the note in the beginning of the post). Otherwise you might have to map your collection as a bag or set instead of a list.

这篇关于如何将新对象添加到映射为NHibernate的一对多的IList?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆