【问题标题】:Why does my class save one collection to the database and not the other?为什么我的班级将一个集合保存到数据库而不是另一个?
【发布时间】:2012-03-23 03:47:53
【问题描述】:

这快把我逼疯了。我可以将其中一个集合保存在课程中,但不能保存另一个。

我有一个班级叫Category

public Category()
{
    Items = new List<Item>();
    Prices = new List<Price>();
}

这两种方法几乎相同。构造函数分别设置了一个名为Category 的属性及其NamePrice

public virtual Item AddItem(string name)
{
    var item = new Item(this, name);
    Items.Add(item);
    return item;
}

public virtual Price AddPrice(decimal price)
{
    var price = new Price(this, price);
    Prices.Add(price);
    return price;
}

映射

public class CategoryMap : ClassMap<Category>
{
    public CategoryMap()
    {
       // Other properties

       HasMany(x=>x.Items).Cascade.AllDeleteOrphan();
       HasMany(x=>x.Prices).Cascade.AllDeleteOrphan();
    }
}

如您所见,这两个集合的映射方式完全相同。

PriceItem 的映射都具有相同的映射

References(x=>x.Category);

据我所知,这两者的几乎所有内容都是相同的。问题来了

category.AddItem(someName);
session.Save(category);    // Works

category.AddPrice(somePrice);
session.Save(category);    // Doesn't work

这些在我用来填充测试数据库的文件中。保存项目工作正常。保存价格不会。类和映射是相同的。我想不通。

映射应该可以正常工作,因为直接调用构造函数可以正常工作

session.Save(new Price(category, 1));

那么,为什么 Category 保存一个集合而不保存另一个集合?我运行了分析器,但该类甚至没有尝试保存 Price 集合。

更新:

正如 Gabe 在评论中指出的那样,如果我交换调用以便在 Item 之前调用 Price,Price 会进入数据库而 Item 不会。

如果我在每次集合更新后调用session.Flush(),它就可以正常工作。我应该这样做吗,还是有办法修复我的映射以使其正常工作?

【问题讨论】:

  • 如果您交换调用顺序(先添加价格,然后添加商品),您会得到相同的行为吗?
  • @GabeMoothart,这很令人惊讶。看起来只有第一个电话正在保存。如果我交换它们,价格会节省,而物品不会。我尝试在通话后拨打session.Flush();,但随后出现错误Cannot update identity column CategoryId
  • @GabeMoothart,没关系。该错误与另一个映射问题有关。您可以发表您的评论作为答案吗? session.flush 有效,但你能告诉我是否应该在每次集合更新后调用它,还是有办法修复我的映射,所以我不必这样做?

标签: c# fluent-nhibernate


【解决方案1】:

尝试交换调用顺序(先添加价格,然后添加商品),看看是否真的是 Price 映射的问题,或者问题是否在于第二次调用失败。

关于flush - 大多数时候您不需要显式调用flush,这是nHibernate 在需要时会在后台执行的操作(details here)。刷新模式不是映射问题(它是您可以设置的会话属性,但通常您也不必这样做)。

如果您将代码包装在事务中,则不需要flush。如果你不是,你应该是,这可能是你的问题。

using (var tx = Session.BeginTransaction()) {

    category.AddItem(someName);
    category.AddPrice(somePrice);
    session.Save(category);

    tx.Commit();
}

更新:我想我知道你的问题是什么。鉴于您的代码,您似乎正在创建一个新的 category 对象并用数据填充它。在第一个Save() 上,nHibernate 执行自动刷新,因为它无法将 category_id 分配给子集合,直到它从数据库中获取一个。但是第二次,category 有一个 id,因此不需要立即刷新会话。 nHibernate 在不需要时不会与数据库聊天。正如我上面提到的,解决方案是始终使用事务来指定您完成工作的时间。

【讨论】:

  • 非常感谢加布。我将考虑将我的代码重构为事务,但现在显式调用 Flush 有效。
  • 如果 category 是一个持久对象(从会话中检索),您甚至不需要调用 session.Save。你可以提交事务。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-08
  • 1970-01-01
  • 2023-03-21
  • 2018-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多