代码之家  ›  专栏  ›  技术社区  ›  Jonny Cundall

使用自定义生成器级联保存nhibernate实体时堆栈溢出

  •  1
  • Jonny Cundall  · 技术社区  · 16 年前

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

    级联保存地址时出现问题,该地址具有自定义ID生成器-地址ID的形式为“ADR000234”,以适应遗留数据库结构。

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

    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类的映射

        <?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没有问题。

    在我看来,当我执行级联保存时,由于某种原因,它无法在过程中运行其他查询,但它没有抛出异常,而是行为异常(一次又一次地重新启动该方法)。我以前从未见过C#方法能做到这一点。我很想知道是否有人知道如何解决这个问题。

    2 回复  |  直到 16 年前
        1
  •  1
  •   Jaguar    16 年前

    我认为问题在于您正在生成器中执行nh查询,并且您正在查询要保存的实体类型。

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

    因此,用原生SqlCommand替换Nh查询(CreateSqlQuery也可以工作),我认为您的问题将得到解决。

        2
  •  1
  •   Thanigainathan    15 年前

    请在端点xml映射中更新关系的所有者。 请在地址和联系人的多对一中提及inverse=“true”。