C# 使用自定义生成器级联保存nhibernate实体时堆栈溢出
我是Nhibernate的新手,所以为冗长的描述道歉 我怀疑改变遗留数据库的结构可能是最好的选择,但我想尝试让NHibernate来处理它 基本上,结构是端点有地址和联系人。端点存储在具有复合ID(地址ID、联系人ID)的表中 级联保存地址时出现问题,该地址具有自定义ID生成器-地址ID的形式为“ADR000234”,以适应遗留数据库结构 自定义ID生成器包含一个查询,当我将地址保存为端点的一部分时,会出现堆栈溢出。当调试光标到达计算查询的行(var maxAddressID..)时,然后跳回到方法的开头,并继续这样做,直到引发堆栈溢出 这是我的发电机课C# 使用自定义生成器级联保存nhibernate实体时堆栈溢出,c#,nhibernate,hibernate,C#,Nhibernate,Hibernate,我是Nhibernate的新手,所以为冗长的描述道歉 我怀疑改变遗留数据库的结构可能是最好的选择,但我想尝试让NHibernate来处理它 基本上,结构是端点有地址和联系人。端点存储在具有复合ID(地址ID、联系人ID)的表中 级联保存地址时出现问题,该地址具有自定义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没有问题
另外,如果我从映射中删除地址和联系人属性(但不是从复合ID中),并在保存端点之前保存地址和联系人,也可以
在我看来,当我执行级联保存时,由于某种原因,它无法在过程中运行其他查询,但它没有抛出异常,而是行为异常(一次又一次地重新启动该方法)。我以前从未见过C#方法能做到这一点。我很想知道是否有人知道如何解决这个问题。我认为问题在于您正在生成器中执行nh查询,并且您正在查询要保存的实体类型 不是在调用Save()时调用生成器,而是在需要刷新/提交数据时调用生成器。现在,Save()将实体放在一个操作队列中,该队列包含要执行的操作。当您调用CreateQuery/CreateCriteria并通过List()/UniqueResult()请求结果时,nhibernate的引擎检测到您对某个实体发出了Save()请求,因此将首先尝试刷新/提交该实体(从而调用生成器),然后执行查询,从而启动无限循环;逻辑是这样的,因为您调用了Save(),然后查询该类类型,所以您希望结果集包含保存的对象
因此,用本机SqlCommand替换您的Nh查询(CreateSqlQuery也可以工作),我认为您的问题将得到解决。请在端点xml映射中更新关系的所有者。 请在地址和联系人的多对一中提及inverse=“true”。
谢谢你能发布地址映射吗?我有一个确切的问题。你能告诉我你是怎么解决的吗?我尝试了CreateSQLQuery(),但收到了相同的StackOverFlow异常。我没有尝试本机SqlCommand方法..是的,因为在FlushMode.Auto上,CreateSqlQuery也可能引发刷新,从而导致问题。您必须使用本机SQLCommands,非常感谢您给我FlushMode提示。我添加了session.FlushMode=FlushMode.Commit;至少对我来说,stackoverflow问题消失了,一切正常。请注意,这意味着,当您时不时地保存实体A时,您进行了一个应返回实体A的查询,但它不会返回实体A(因为该实体尚未被持久化)