堆栈溢出,同时使用自定义生成器级联保存nhibernate实体 [英] Stack Overflow whilst cascade saving nhibernate entity with custom generator

查看:100
本文介绍了堆栈溢出,同时使用自定义生成器级联保存nhibernate实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对Nhibernate来说还很陌生,所以为冗长的描述而道歉

I'm pretty new to Nhibernate, so apologies for a long - winded description

我怀疑更改遗留数据库的结构可能是最好的选择,但是我想尝试让NHibernate处理它.

I suspect that changing the structure of the legacy DB is probably the best option, but I want to try and get NHibernate to deal with it.

基本上,此结构是一个EndPoint具有一个地址和一个联系人.端点存储在具有复合ID(地址ID,联系人ID)的表中.

Basically the structure is this an EndPoint has an address and a contact. Endpoint is stored in a table with a composite ID (Address ID, Contact ID).

当级联保存一个具有自定义ID生成器的地址时,我遇到了一个问题-地址ID的格式为"ADR000234",以适应旧版DB结构.

I'm having a problem when cascade saving an address, which has a custom ID generator - address ID are of the form "ADR000234" to fit in with a legacy DB structure.

自定义ID生成器包含一个查询,当我将该地址保存为端点的一部分时,会出现堆栈溢出.调试时,光标进入评估查询的行(var maxAddressID ..),然后跳回该方法的开头,并继续执行此操作,直到引起堆栈溢出为止.

The custom ID generator includes a query, and when I save the address as part of an endpoint, I get a stack overflow. When debugging the cursor gets to line that evaluates the query( var maxAddressID..), then jumps back to start of the method, and keeps on doing this until it raises a stack overflow.

这是我的生成器类

public class AddressIdGenerator :  IIdentifierGenerator
{
    public object Generate(ISessionImplementor session, object obj)
    {
        var castAsSession = (ISession)session;
        var allAddresses = castAsSession.CreateQuery("select max(Code) from Address a");
        var maxAddressID = (string)allAddresses.List()[0];
        var previousNumber = int.Parse(maxAddressID.Substring(3, 6));

        return GetNewId("ADR", previousNumber);
    }

    private string GetNewId(string prefix, int number)
    {
        return prefix + (number + 1).ToString().PadLeft(6, '0');
    }
}

这是我对Endpoint CLass的映射

Here's my mapping foe the EndPoint CLass

    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
    assembly="DataClasses"
    namespace="DataClasses">
    <class name="EndPoint" table="[Addresses_Contacts]">
    <composite-id>
    <key-property name ="Address" column ="[Address ID]" type="string" />
    <key-property name ="Contact" column ="[Contact ID]" type="string"/>
    </composite-id>

    <many-to-one name="Address" class="DataClasses.Address, DataClasses" cascade="save-update"/>
    <many-to-one name="Contact" class="DataClasses.Contact, DataClasses" cascade="save-update"/>

    </class>
    </hibernate-mapping>

以及地址映射:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DataClasses" namespace="DataClasses">
<class name="Address" table="[Lookup Addresses]" >
<id name="Code" column="ID" type="string">
  <generator class="Nhibernate.AddressIdGenerator, Nhibernate" />
</id>
<property name="OrganisationName" column="[Name of Organisation]"/>
<property name="StreetAddress1" column="[Park/centre/estate]" />
<property name="StreetAddress2" column="[Street Name]" />
<property name="Town" column="[Town/City]" />
<property name="State" column="[Region/ State]" />
<property name="PostCode" column="[Postal/ Area Code]" />
<property name="District" column="[Local District]" />
<property name="Airport" column="[Airport code]" />
<many-to-one name="Country" class="DataClasses.Country, DataClasses" column ="[Country Code]"/>
</class>
</hibernate-mapping>

如果我尝试单独保存并寻址,则可以正常工作,并且ID不会出现问题.

If I try to save and Address on its own, it works fine, the ID is generated with no problems.

如果我从映射中删除了Address和Contact属性(但没有从复合ID中删除),并在保存Endpoint之前保存了Address和Contact,那也没问题.

Also if I remove the Address and Contact properties from the mapping (but not from the composite ID), and save the Address and Contact before saving the Endpoint, it's fine too.

在我看来,当我执行级联保存时,由于某种原因它无法在该过程中运行其他查询,但是与其引发异常,它的行为很奇怪(一次又一次地重新启动该方法).我以前从未见过C#方法执行此操作.我很想知道是否有人知道如何解决这个问题.

It seems to me that when I'm doing the cascade save, for some reason it can't run other queries during the process, but rather than throwing an exception it's behaving strangely (restarting the method again and again). I haven't ever seen a C# method do this before. I'd love to know if anyone has an idea of how to fix this.

推荐答案

我认为问题出在您正在Generator内进行nh查询,并且正在查询要保存的实体类型.

i'm thinking that the problem resides that you are doing an nh-query inside the Generator and you are querying the entity type you want to save.

不是在您调用Save()时调用生成器,而是在需要刷新/提交数据时调用该生成器.现在,Save()将实体放置在要执行的操作的动作队列上.当您调用CreateQuery/CreateCriteria并通过List()/UniqueResult()请求结果时,nhibernate的引擎会检测到您对实体进行了Save()请求,因此将尝试首先刷新/提交实体(从而调用生成器)然后执行查询,从而开始无限循环;逻辑是这样的,因为您调用了Save()之后又要查询该类类型,所以您希望结果集包含Saved对象.

The generator is called not when you call Save() but whenever there is a need to flush/commit the data. Now, Save() places the entity on a action-queue of things to do. When you call CreateQuery/CreateCriteria and request the result via List()/UniqueResult() nhibernate's engine detects that you made a Save() request on an entity and so will try to flush/commit the entity first (and thus call the generator) and then perform the query and thus start an infinite loop; The logic is such that since you called Save() and then you are querying that class type you will want the result set to include the Saved object.

因此,用本机SqlCommand替换您的Nh查询(CreateSqlQuery也有可能工作),我认为您的问题将得到解决.

So, replace your Nh-query with a native SqlCommand (there is a possibility CreateSqlQuery will work too) and i think your problem will be solved.

这篇关于堆栈溢出,同时使用自定义生成器级联保存nhibernate实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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