使用Fluent NHibernate将新项添加到集合中不会在DB中插入新行

时间:2014-01-20 23:56:36

标签: c# nhibernate fluent-nhibernate

我有一个名为ShoppingLists的模型,每个ShoppingLists都有一个名为ShoppingListItems的{​​{1}}集合。我喜欢能够做的是在我的列表中添加一个新项目:

Items

我希望dbList.Items.Add(new ShoppingListItems(Guid.NewGuid(), identity.UserId, source.Raw)); 自动链接到其父ShoppingListItems类,并且NHibernate在事务时创建适当的SQL ShoppingLists语句承诺。但是,我得到了例外:

INSERT

我需要做的是创建对象,保存它,然后将其添加到集合中:

NHibernate.StaleStateException was unhandled
  HResult=-2146232832
  Message=Unexpected row count: 0; expected: 1
  Source=NHibernate

我想消除这样做的必要性。我对var newItem = new ShoppingListItems(Guid.NewGuid(), identity.UserId, source.Raw); newItem.ShoppingList = dbList; session.Save(newItem); dbList.Items.Add(newItem); 的映射是这样的:

ShoppingLists

我对Id(x => x.ShoppingListId); Map(x => x.UserId).Not.Nullable(); Map(x => x.Title).Not.Nullable(); HasMany(x => x.Items) .KeyColumn("ShoppingListId") .Cascade.Delete(); // If Shopping List is deleted, delete all the Items that reference this list 的映射是:

ShoppingListItems

我尝试过各自使用Id(x => x.ItemId); Map(x => x.Raw).Length(50); Map(x => x.Qty); Map(x => x.Unit); Map(x => x.UserId).Not.Nullable(); Map(x => x.CrossedOut).Not.Nullable(); References(x => x.Recipe).Column("RecipeId"); References(x => x.Ingredient).Column("IngredientId"); References(x => x.ShoppingList).Column("ShoppingListId"); ,但不能避免。有什么想法吗?

2 个答案:

答案 0 :(得分:1)

此处的问题与处理ShoppingListItem Guid ID 有关(请参阅问题中的项目创建的代码段)

“工作”方案,在创建并保留ShoppingListItem时,执行以下步骤 - 生成Guid ID并将其传递给构造函数

var newItem = new new ShoppingListItems(Guid.NewGuid()...)

接下来,要求NHiberante执行session.Save(newItem),因此发出INSERT语句......

但是在第二种情况下会发生什么情况,当session.Save(newItem)未被调用时,只有Add()项目进入父ShoppingLists的集合?

如上所述:5.1.4.7. Assigned Identifiers(摘录)

  

...使用已分配的生成器的实体无法通过ISession的SaveOrUpdate()方法保存。相反,如果要保存或更新对象,则必须明确指定NHibernate ...

NHibernate在这种情况下做什么(当调用session.Flush()时)猜测:应该为每个集合项发出INSERT还是UPDATE?

说到newItem,它会将Guid ID与UnsavedValue()进行比较,在这种情况下为Guid.Empty

  

此比较将导致决定:发出UPDATE语句,Guid ID不代表新对象。

执行UPDATE。数据库响应:已完成更新,无错误,但 行已更新*。 NHibernate抛出:

  

意外的行数:0;预期:1

解决方案

将GUID生成留在NHibernate上。 E.g:

Id(x => x.ItemId)
  .GeneratedBy.GuidComb()
  .UnsavedValue(Guid.Empty);

而且,明确地将newItem引用设置为其父级,使用Inverse()设置优化级联

// both assignments
newItem.ShoppingList = dbList;
dbList.Items.Add(newItem);

使用inverse映射的列表:

// improved write operations handling
HasMany(x => x.Items)
   .KeyColumn("ShoppingListId")
   .Inverse()
   ...

答案 1 :(得分:0)

请重新检查ShoppingListItems的映射

你必须做一个级联全部,反过来应该是真的

购物清单和商品之间存在双向关联。

您可以通过将两个多对多关联映射到同一个数据库表并将一端声明为反向来指定双向多对多关联。