【问题标题】:Nhibernate one-to-many causes insert problemsNhibernate 一对多导致插入问题
【发布时间】:2015-07-16 14:28:34
【问题描述】:

我正在尝试添加新的交叉引用表以将帐户与包相关联,当我尝试保存帐户时遇到了一个奇怪的问题。

这个交叉引用表有它自己的属性,所以我使用它们的集合而不是包。

当我在 Account 上调用 SaveOrUpdate 时会发生什么,NHibernate 显然决定尝试用 null 对象填充其他 Account 属性(如 Product)。我已经验证,注释掉新映射不再导致 Product setter 受到打击。 (它也会命中其他多对一映射对象,Product 没什么特别的,这只是一个例子)。

还需要注意的是,这仅在插入时发生。在更新和插入时,我们将从一些表单输入中设置 ProductFk。更新时 Account.Product 已经通过从数据库中检索 Account 进行设置。插入时,会创建一个新帐户,其中设置了 ProductFk 但未设置 Product。我怀疑 Product 为 null 会导致 NHibernate 在插入之前尝试填充它,但不明白为什么添加这个新映射会触发它。

这是我的帐户映射文件:

 <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="kpa.mko.dal" namespace="kpa.mko.dal.Entities.Accounts">
<class name="Account" table="Accounts">
    <id name="AccountId" type="Int32" unsaved-value="0">
        <generator class="identity" />
    </id>
    <property name="ParentAccountFk" />
    <many-to-one name="ParentAccount" column="ParentAccountFk" insert="false" update="false" />

    <property name="ProductFk" not-null="true" />
    <many-to-one name="Product" column="ProductFk" insert="false" update="false" />
    <property name="DistrictFk" not-null="true" />
    <many-to-one name="District" column="DistrictFk" insert="false" update="false" />
    <property name="Address1" />
    <snipped out other plain properties like Address1 />
    <set name="AccountPackageXrefs" table="Account_Package_xref" inverse="true">
        <key column="AccountFk"/>
        <one-to-many class="Account_Package_xref" />
    </set>
    <sql-insert>
        exec up_gen_Account_Insert @ParentAccountFk = ?, @ExternalAccountId = ?, @ClientAccountNumber = ?, @AccountName = ?
        ,@LogoFk = ?, @AccountTypeFk = ?, @AccountStatusFk = ?, @IsBillableAccount = ?, @ProductFk = ?, @HotLinkAccount = ?
        ,@FormGroupFk = ?, @DistrictFk = ?, @PrimaryEngineerFk = ?, @SecondaryEngineerFk = ?
        ,@Address1 = ?,@Address2 = ?,@City = ?,@StateFk = ?,@Zip = ?,@Country = ?,@Phone = ?,@Fax = ?,@TollFreeNumber = ?
        ,@BillingAddress1 = ?,@BillingAddress2 = ?,@BillingCity = ?,@BillingStateFk = ?,@BillingZip = ?,@BillingCountry = ?
        ,@BillingContactName = ?,@BillingContactPhone = ?,@BillingContactEmail = ?
        ,@TermDate = ?,@VisitValue = ?, @AccountIndustryTypeFk = ?, @CreatedByFk = ?,@CreatedDate = ?,@ModifiedByFk = ?,@ModifiedDate = ?
    </sql-insert>
</class>

还有我的 Account_Package_xref 映射:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="kpa.mko.dal" namespace="kpa.mko.dal.Entities.Accounts">
<class name="Account_Package_xref" table="Account_Package_xref">
    <id name="AccountPackageId" type="Int32" unsaved-value="0">
        <generator class="identity" />
    </id>
    <property name="AccountFk"/>
    <property name="PackageFk"/>
    <property name="PrimaryConsultantFk"/>
    <property name="SecondaryConsultantFk" />
    <property name="CreatedById" column="CreatedByFk" not-null="true" update="false" />
    <property name="CreatedDate" not-null="true" update="false" />
    <property name="ModifiedById" column="ModifiedByFk" not-null="true" />
    <property name="ModifiedDate" not-null="true" />

    <many-to-one name="Account" column="AccountFk" not-null="true" insert="false" update="false"/>
    <many-to-one name="Package" column="PackageFk" not-null="true" insert="false" update="false"/>
</class>
<sql-query name="Account_Pacakge_xref_GetForAccountAndPackage">
    <return class="Account_Package_xref"/>
    exec Account_Package_xref_GetForAccountAndPackage @accountId = :accountId, @packageId = :packageId
</sql-query>

所以当我在插入时执行这个

NHibernateSession.SaveOrUpdate(entity);

我看到 Account 的 setter 中的断点为空值(当然,这会失败。)

public virtual ServicesProduct Product
{
    get { return _product; }
    set { 
        _product = value;
        ProductFk = value.ProductId;
    }
}

但只有当我包含新映射时。所以,这是关于尝试添加这个我真的不明白的新集合。

当我构建一个新帐户时,除了 ProductFk 之外,我可能还可以添加设置产品,但这是一种解决方法,并不能解释为什么添加这种新关系会导致系统对产品采取不同的行为(例如属性)。

【问题讨论】:

    标签: c# nhibernate nhibernate-mapping


    【解决方案1】:

    ORM 世界的重点是 (好吧,也许只是 NH​​ibernate)

    • ValueType(string including) 的分配按原样处理。当该值的原始来源发生变化时,它不再被重新检查(重新评估、重新分配)
    • ReferenceType 的分配不同。分配给属性的引用 (Product) 表示 C# 引用。在那一刻,Product_ID 未被解析并被未分配。因此,NHibernate 可以等待ISession.Flush() 并根据需要正确订购所有 INSERT 语句。
      • 首先插入产品...
      • 它的Product_ID 被检索...
      • 并可用于根实体的 INSERT - 作为 Product_ID 值

    要使所有这些都正常工作,我们只需更改此映射

    // not the right way with ORM
    <property name="ProductFk" not-null="true" />
    <many-to-one name="Product" column="ProductFk" insert="false" update="false" />
    <property name="DistrictFk" not-null="true" />
    <many-to-one name="District" column="DistrictFk" insert="false" update="false" />
    

    这是关于由 NHiberante 管理的 ValueType,进入参考管理:

    // object relations are mapped. That is ORM
    <property name="ProductFk" not-null="true" insert="false" update="false" />
    <many-to-one name="Product" column="ProductFk" />
    <property name="DistrictFk" not-null="true" insert="false" update="false" />
    <many-to-one name="District" column="DistrictFk" />
    

    另外,因为有一些 sql-insert 有一些 存储过程 (你仍然被一些数据库人员强迫这样做吗?,没门如何避免?),我建议像这样调整实体映射

    // fields
    Product _product;
    
    // properties
    public virtual int ProductFk { get; set; }
    public virtual Product Product
    {
        get { return _product; }
        set
        {
            _product = value;
            ProductFk = _product != null ? _product.ProductId : 0;
        }
    }
    

    【讨论】:

    • Radim,谢谢你的想法,但运气不好。典型的继承代码,开发此代码的人早已不复存在。我不知道他们为什么选择 sql-insert(大多数映射都有一个命名查询来工作)。问题是将我的新集添加到映射中会导致 NHIbernate 开始在产品中设置 null;删除该映射,它没有。为什么添加一个新集合会导致 NHIbernate 说“我应该开始影响这些其他属性”,我不明白。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多