NHibernate将0保存到many-to-one列而不是null。

3

我有一个Donations表,其中包含一个与Campaigns表相关联的CampaignID列。如果Campaign未被用于此捐赠,我需要在CampaignID列中插入0而不是Null。

我的Donations表映射如下:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
    <class name="Donation,Entities" lazy="true" table="Donations" dynamic-update="true" >
        <id name="DonationID" column="PledgeID" type="Int64">
            <generator class="native" />
        </id>
        <many-to-one name="FundraisingCampaign" class="Campaign, Entities" column="CampaignID" lazy="proxy" not-found="ignore" cascade="none" />

在保存到数据库之前,我会检查我的捐赠实体中的活动实体是否为空。如果是,则将其设置为新的活动实体,并将活动ID设置为0,如下所示。

    if (null == donation.FundraisingCampaign)
    {
        donation.FundraisingCampaign = new Campaign() {CampaignID = 0};
    }

问题在于我在保存时收到一个错误消息"对象引用未保存的瞬态实例-在刷新之前保存瞬态实例。"
我不明白为什么它关心我Campaign对象上的任何内容,除了CampaignID之外,因为我已经设置了cascade="none",它不应该尝试将任何内容保存到Campaign表中。
由于当前系统的限制,我被迫在那里设置0而不是Null,因此无法保存Null。
2个回答

3
尝试从数据库中加载DB标识为0的Campaign对象。这将是一个完全持久化的对象。然后,您应该能够设置它并持久化捐赠。
如果这个方法有效,您需要更改Campaign对象的ID属性映射。NH无法确定您在此处创建的瞬态活动对象。请注意保留HTML标记。
new Campaign() {CampaignID = 0};

实际上是一个独立的对象。你应该在映射中添加一个“未保存的值”,比如-1。这样,Nh就可以区分具有DB标识符Id为0的有效分离式广告系列和具有Id为-1的临时新广告系列。然后记得将新创建的广告系列的Id设置为-1。


我将我的"未保存值"设置为-1,并更新了所有代码,以便在创建新项目时将 CampaignID 设置为-1。现在,我的 CampaignID 值为0而不是Null。感谢Noel。 - Adam
使用可空类型一直更加容易。 - Stefan Steinegger

2
  1. NHibernate可以通过检查主键来确定实体是否已经存储。如果主键为0,则表示未存储。您可以在映射中更改此行为。
  2. 如果您尝试保存实体,则所有引用实体都必须级联或已存储。这对于NHibernate获取外键非常重要。它不能将外键指向内存,而必须在数据库中,因此必须存储。如果不是这种情况,您将会得到异常消息。

通过这些信息,您应该了解为什么会出现问题。

CampaignID是否使用自动计数器生成?那么它无论如何都不起作用。(您无法在应用程序中设置id)。除非您将CampaignID设置为0(请参见下文)。

您可以将CampaignID设置为可空int,然后默认情况下未保存的值为null。

请注意,您的数据库中将会有一个CampaignID=0的Campaign。这是一个“Null Object”。您需要存储它,例如在设置完数据库之后。

如果您想避免空对象,您将会遇到麻烦。NHibernate概念上不允许您访问外键,它会为您管理。您可能可以做一些技巧(例如在拦截器中),但我认为这不值得麻烦。您还必须确保没有外键约束,这也不好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接