NHibernate Composite-ID子级联异常

save2king

我在一段时间内遇到过nhibernate问题,但从未解决过,请尝试清楚地描述问题。我想使用NHibernate的功能来级联保存和编辑通过FK连接到父对象的对象列表。我不明白我在哪里错了,谁能帮助我?

数据库上的表是:

CREATE TABLE [Evento].[Eventi](
    [CodiceEvento] [varchar](20) NOT NULL,
    [CodiceTipoEvento] [smallint] NOT NULL,
    [CodiceTipoAltroEvento] [smallint] NULL,
    [CodiceTipoClasseEvento] [tinyint] NOT NULL,
    [CodiceTipoCausaEvento] [tinyint] NULL,
    [CodiceTipoStatoSchedaEvento] [tinyint] NOT NULL,
    [DescrizioneEvento] [varchar](1000) NULL
 CONSTRAINT [PK_Eventi] PRIMARY KEY CLUSTERED 
(
    [CodiceEvento] ASC
)


CREATE TABLE [Evento].[EventiDettaglioBeneInteressato](
    [CodiceEvento] [varchar](20) NOT NULL,
    [PrgOrdinamento] [tinyint] NOT NULL,
    [CodiceTipoBeneRFI] [smallint] NOT NULL,
    [DescrizioneAltroBeneRFI] [varchar](255) NULL,
    [CodiceTipoRame] [varchar](25) NULL,
    [CodiceTipoUnitaMisura] [tinyint] NULL,
    [NumQuantita] [bigint] NULL,
 CONSTRAINT [PK_EventiDettaglioBeneInteressato] PRIMARY KEY CLUSTERED 
(
    [CodiceEvento] ASC,
    [PrgOrdinamento] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [Evento].[EventiDettaglioBeneInteressato]  WITH NOCHECK ADD  CONSTRAINT [FK_EventiDettaglioBeneInteressato_Eventi] FOREIGN KEY([CodiceEvento])
REFERENCES [Evento].[Eventi] ([CodiceEvento])
ON DELETE CASCADE
NOT FOR REPLICATION 
GO

映射Evento:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping assembly="Data.Model" namespace="Data.Model.Domain.Eventi" xmlns="urn:nhibernate-mapping-2.2">
  <class name="Eventi" table="Eventi" lazy="true" schema="Evento">
    <id name="CodiceEvento" column="CodiceEvento" />

    <many-to-one name="TipiEvento" update="false" insert="false">
      <column name="CodiceTipoEvento" sql-type="smallint" not-null="true" />
    </many-to-one>
    <property name="CodiceTipoEvento" >
      <column name="CodiceTipoEvento" sql-type="smallint" not-null="true" />
    </property>

    <many-to-one name="TipiAltroEvento" update="false" insert="false">
      <column name="CodiceTipoAltroEvento" sql-type="smallint" not-null="false" />
    </many-to-one>
    <property name="CodiceTipoAltroEvento" >
      <column name="CodiceTipoAltroEvento" sql-type="smallint" not-null="false" />
    </property>

    <many-to-one name="TipiClasseEvento" update="false" insert="false">
      <column name="CodiceTipoClasseEvento" sql-type="tinyint" not-null="true" />
    </many-to-one>
    <property name="CodiceTipoClasseEvento">
      <column name="CodiceTipoClasseEvento" sql-type="tinyint" not-null="true" />
    </property>

    <many-to-one name="TipiCausaEvento" update="false" insert="false">
      <column name="CodiceTipoCausaEvento" sql-type="tinyint" />
    </many-to-one>
    <property name="CodiceTipoCausaEvento" >
      <column name="CodiceTipoCausaEvento" sql-type="tinyint" />
    </property>

    <many-to-one name="TipiStatoSchedaEvento" update="false" insert="false">
      <column name="CodiceTipoStatoSchedaEvento" sql-type="tinyint" not-null="true" />
    </many-to-one>
    <property name="CodiceTipoStatoSchedaEvento">
      <column name="CodiceTipoStatoSchedaEvento" sql-type="tinyint" not-null="true" />
    </property>

    <many-to-one name="GestoriAsset" update="false" insert="false">
      <column name="CodiceGestoreAsset" sql-type="int" not-null="false" />
    </many-to-one>
    <property name="CodiceGestoreAsset">
      <column name="CodiceGestoreAsset" sql-type="int" not-null="false" />
    </property>

    <many-to-one name="TipiOraEvento" update="false" insert="false">
      <column name="CodiceTipoOraEvento" sql-type="tinyint" not-null="false" />
    </many-to-one>
    <property name="CodiceTipoOraEvento">
      <column name="CodiceTipoOraEvento" sql-type="tinyint" not-null="false" />
    </property>

    <many-to-one name="TipiAutoreEvento" update="false" insert="false">
      <column name="CodiceTipoAutoreEvento" sql-type="smallint" not-null="false" />
    </many-to-one>
    <property name="CodiceTipoAutoreEvento">
      <column name="CodiceTipoAutoreEvento" sql-type="smallint" not-null="false" />
    </property>

    <many-to-one name="TipiSegnalazioneEvento" update="false" insert="false">
      <column name="CodiceTipoSegnalazioneEvento" sql-type="smallint" not-null="false" />
    </many-to-one>
    <property name="CodiceTipoSegnalazioneEvento">
      <column name="CodiceTipoSegnalazioneEvento" sql-type="smallint" not-null="false" />
    </property>

    <property name="DescrizioneEvento">
      <column name="DescrizioneEvento" sql-type="varchar" not-null="false" />
    </property>

    <bag name="EventiDettaglio" table="EventiDettaglioBeneInteressato" schema="Evento" inverse="true" cascade="all,delete-orphan" >
      <key column="CodiceEvento" />
      <one-to-many class="EventiDettaglioBeneInteressato" />
    </bag> 

</class>
</hibernate-mapping>

领域模型:

using System;
using System.Text;
using System.Collections.Generic;
using Data.Model.Attributes;

namespace Data.Model.Domain.Eventi
{

    [Serializable, Observable]
    public class Eventi : Entity, IEntity
    {

        public Eventi()
        {
            EventiDettaglio = new List<EventiDettaglioBeneInteressato>();
        }

        public virtual string CodiceEvento { get; set; }
        public virtual string DescrizioneEvento { get; set; }

        public virtual TipiEvento TipiEvento { get; set; }
        public virtual TipiAltroEvento TipiAltroEvento { get; set; }
        public virtual TipiClasseEvento TipiClasseEvento { get; set; }
        public virtual TipiCausaEvento TipiCausaEvento { get; set; }
        public virtual TipiStatoSchedaEvento TipiStatoSchedaEvento { get; set; }
        public virtual GestoriAsset GestoriAsset { get; set; }
        public virtual TipiOraEvento TipiOraEvento { get; set; }
        public virtual TipiAutoreEvento TipiAutoreEvento { get; set; }
        public virtual TipiSegnalazioneEvento TipiSegnalazioneEvento { get; set; }

        public virtual short CodiceTipoEvento { get; set; }
        public virtual short? CodiceTipoAltroEvento { get; set; }
        public virtual byte CodiceTipoClasseEvento { get; set; }
        public virtual byte? CodiceTipoCausaEvento { get; set; }
        public virtual byte CodiceTipoStatoSchedaEvento { get; set; }
        public virtual int? CodiceGestoreAsset { get; set; }
        public virtual byte? CodiceTipoOraEvento { get; set; }
        public virtual short? CodiceTipoAutoreEvento { get; set; }
        public virtual short? CodiceTipoSegnalazioneEvento { get; set; }       

        public virtual IList<EventiDettaglioBeneInteressato> EventiDettaglio { get; set; }


        #region NHibernate Composite Key Requirements
        public override bool Equals(object obj)
        {
            if (obj == null) return false;
            var t = obj as Eventi;
            if (t == null) return false;
            if (CodiceEvento == t.CodiceEvento)
                return true;

            return false;
        }
        public override int GetHashCode()
        {
            int hash = GetType().GetHashCode();
            hash = (hash * 397) ^ CodiceEvento.GetHashCode();

            return hash;
        }
        #endregion
    }
}

事件映射

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping assembly="Data.Model" namespace="Data.Model.Domain.Eventi" xmlns="urn:nhibernate-mapping-2.2">
  <class name="EventiDettaglioBeneInteressato" table="EventiDettaglioBeneInteressato" schema="Evento" lazy="true" >

    <composite-id>
      <key-property name="PrgOrdinamento" column="PrgOrdinamento" />
      <key-many-to-one class="Data.Model.Domain.Eventi.Eventi, Data.Model" name="Evento">
        <column name="CodiceEvento" />       
      </key-many-to-one> 
    </composite-id>   


    <property name="DescrizioneAltroBeneRFI">
      <column name="DescrizioneAltroBeneRFI" sql-type="varchar" not-null="false" />
    </property>
    <property name="NumQuantita">
      <column name="NumQuantita" sql-type="bigint" not-null="false" />
    </property>

    <many-to-one name="TipiBeneRFI" update="false" insert="false">
      <column name="CodiceTipoBeneRFI" sql-type="smallint" not-null="true" />
    </many-to-one>
    <property name="CodiceTipoBeneRFI">
      <column name="CodiceTipoBeneRFI" sql-type="smallint" not-null="true" />
    </property>

    <many-to-one name="TipiRame" update="false" insert="false">
      <column name="CodiceTipoRame" sql-type="varchar" not-null="false" />
    </many-to-one>
    <property name="CodiceTipoRame">
      <column name="CodiceTipoRame" sql-type="varchar" not-null="false" />
    </property>

    <many-to-one name="TipiUnitaMisura" update="false" insert="false">
      <column name="CodiceTipoUnitaMisura" sql-type="tinyint" not-null="false" />
    </many-to-one>
    <property name="CodiceTipoUnitaMisura">
      <column name="CodiceTipoUnitaMisura" sql-type="tinyint" not-null="false" />
    </property>

  </class>
</hibernate-mapping>

领域模型:

using System;
using System.Text;
using System.Collections.Generic;
using NHibernate.Proxy;

namespace Data.Model.Domain.Eventi
{
    [Serializable]
    public class EventiDettaglioBeneInteressato : Entity, IEntity
    {
        public virtual Eventi Evento { get; set; }
        public virtual byte PrgOrdinamento { get; set; }

        public virtual TipiBeneRFI TipiBeneRFI { get; set; }
        public virtual TipiRame TipiRame { get; set; }
        public virtual TipiUnitaMisura TipiUnitaMisura { get; set; }


        public virtual short CodiceTipoBeneRFI { get; set; }
        public virtual string CodiceTipoRame { get; set; }
        public virtual byte? CodiceTipoUnitaMisura { get; set; }


        public virtual string DescrizioneAltroBeneRFI { get; set; }
        public virtual long? NumQuantita { get; set; }

        #region NHibernate Composite Key Requirements
        public override int GetHashCode()
        {
            unchecked
            {
                int hash = GetType().GetHashCode();
                hash = (hash * 397) ^ PrgOrdinamento.GetHashCode();
                hash = (hash * 397) ^ (Evento == null ? 0.GetHashCode() : Evento.GetHashCode());
                return hash;
            }
        }

        public override bool Equals(object obj)
        {
            return Equals(obj as EventiDettaglioBeneInteressato);
        }

        public virtual bool Equals(EventiDettaglioBeneInteressato other)
        {
            if (other == null)
            {
                return false;
            }

            if (ReferenceEquals(other, this))
            {
                return true;
            }

            var otherType = NHibernateProxyHelper.GetClassWithoutInitializingProxy(other);
            var thisType = NHibernateProxyHelper.GetClassWithoutInitializingProxy(this);
            if (!otherType.Equals(thisType))
            {
                return false;
            }

            bool otherIsTransient = Equals(other.Evento, null) && Equals(other.PrgOrdinamento, 0);
            bool thisIsTransient = Equals(Evento, null) && Equals(PrgOrdinamento, 0);
            if (otherIsTransient || thisIsTransient)
                return false;

            return Equals(other, this);
        }

        private bool Equals(EventiDettaglioBeneInteressato a, EventiDettaglioBeneInteressato b)
        {
            if (a.Evento == b.Evento
                && a.PrgOrdinamento == b.PrgOrdinamento)
                return true;

            return false;
        }
        #endregion
    }
}

测试:

    [TestMethod]
    public void EventoTest_Add_Child_BeniInteressati()
    {
        var codiceEvento = "20140630_013325_BA";
        using (var session = IoC.Container.Resolve<ISessionFactory>().OpenSession())
        {
            var evento = session.Get<Data.Model.Domain.Eventi.Eventi>(codiceEvento);

            Assert.AreEqual(evento.EventiDettaglio.Count, 0);

            var beneInteressato = new Data.Model.Domain.Eventi.EventiDettaglioBeneInteressato();
            beneInteressato.PrgOrdinamento = 1;
            beneInteressato.Evento = evento;
            beneInteressato.CodiceTipoBeneRFI = 1;

            evento.EventiDettaglio.Add(beneInteressato);

            var beneInteressato2 = new Data.Model.Domain.Eventi.EventiDettaglioBeneInteressato();
            beneInteressato.PrgOrdinamento = 2;
            beneInteressato.Evento = evento;
            beneInteressato.CodiceTipoBeneRFI = 2;

            evento.EventiDettaglio.Add(beneInteressato2);

            session.SaveOrUpdate(evento);
            session.Flush();
        }
    }

Error:

Message:
Cannot insert the value NULL into column 'CodiceEvento', table 'Evento.EventiDettaglioBeneInteressato'; column does not allow nulls. INSERT fails.
The statement has been terminated.

StackTrace:
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
   at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
   at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
   at System.Data.SqlClient.SqlCommand.ExecuteBatchRPCCommand()
   at System.Data.SqlClient.SqlCommandSet.ExecuteNonQuery()
   at NHibernate.AdoNet.SqlClientSqlCommandSet.ExecuteNonQuery()
   at NHibernate.AdoNet.SqlClientBatchingBatcher.DoExecuteBatch(IDbCommand ps)

LOG:

18:15:25.695 [10] WARN  NHibernate.Engine.ForeignKeys - Unable to determine if Data.Model.Domain.Eventi.EventiDettaglioBeneInteressato with assigned identifier Data.Model.Domain.Eventi.EventiDettaglioBeneInteressato is transient or detached; querying the database. Use explicit Save() or Update() in session to prevent this.
18:15:25.716 [10] WARN  NHibernate.Engine.ForeignKeys - Unable to determine if Data.Model.Domain.Eventi.EventiDettaglioBeneInteressato with assigned identifier Data.Model.Domain.Eventi.EventiDettaglioBeneInteressato is transient or detached; querying the database. Use explicit Save() or Update() in session to prevent this.
18:15:25.960 [10] WARN  NHibernate.Util.ADOExceptionReporter - System.Data.SqlClient.SqlException (0x80131904): Cannot insert the value NULL into column 'CodiceEvento', table 'Evento.EventiDettaglioBeneInteressato'; column does not allow nulls. INSERT fails.
The statement has been terminated.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
   at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
   at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
   at System.Data.SqlClient.SqlCommand.ExecuteBatchRPCCommand()
   at System.Data.SqlClient.SqlCommandSet.ExecuteNonQuery()
   at NHibernate.AdoNet.SqlClientSqlCommandSet.ExecuteNonQuery()
   at NHibernate.AdoNet.SqlClientBatchingBatcher.DoExecuteBatch(IDbCommand ps)
ClientConnectionId:b0edabca-f2b9-4cc5-95b8-120653b5dc31
18:15:26.012 [10] ERROR NHibernate.Util.ADOExceptionReporter - Cannot insert the value NULL into column 'CodiceEvento', table 'Evento.EventiDettaglioBeneInteressato'; column does not allow nulls. INSERT fails.
The statement has been terminated.
18:15:26.047 [10] ERROR NHibernate.Event.Default.AbstractFlushingEventListener - Could not synchronize database state with session
NHibernate.Exceptions.GenericADOException: could not execute batch command.[SQL: SQL not available] ---> System.Data.SqlClient.SqlException: Cannot insert the value NULL into column 'CodiceEvento', table 'Evento.EventiDettaglioBeneInteressato'; column does not allow nulls. INSERT fails.
The statement has been terminated.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
   at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
   at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
   at System.Data.SqlClient.SqlCommand.ExecuteBatchRPCCommand()
   at System.Data.SqlClient.SqlCommandSet.ExecuteNonQuery()
   at NHibernate.AdoNet.SqlClientSqlCommandSet.ExecuteNonQuery()
   at NHibernate.AdoNet.SqlClientBatchingBatcher.DoExecuteBatch(IDbCommand ps)
   --- End of inner exception stack trace ---
   at NHibernate.AdoNet.SqlClientBatchingBatcher.DoExecuteBatch(IDbCommand ps)
   at NHibernate.AdoNet.AbstractBatcher.ExecuteBatchWithTiming(IDbCommand ps)
   at NHibernate.AdoNet.AbstractBatcher.ExecuteBatch()
   at NHibernate.Engine.ActionQueue.ExecuteActions(IList list)
   at NHibernate.Engine.ActionQueue.ExecuteActions()
   at NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session)

谢谢。救世主

霍格威德

首先,我在代码中看到了一些“文本”错误,但是我认为这是一个简单的书写错误;-)对问题的处理顺序是:

  1. 使用子对象的集合以及级联时,首先需要像使用时那样使用Inverse,因为这告诉nhibernate首先保存根对象,然后将root-saved-object-key分配给每个子对象。被保存。但这不是使级联正常工作的唯一方法。
  2. 使用像您一样的子对象的双向引用集合时,如果您有一个带有孩子的根,并且每个孩子都有对其根的引用,那么通过向其中添加项来直接在根内的子列表上工作并不是一件好事那是因为添加子对象时,根负责设置每个子根引用。为此,要涉及的步骤是:
    • IList<EventiDettaglioBeneInteressato>Eventi内部添加一个私有字段,然后在构造函数中将其初始化为它们的新空集合
    • Eventi内部,EventiDettaglio属性从更改IList<EventiDettaglioBeneInteressato>IEnumerable<EventiDettaglioBeneInteressato>
    • Eventi内部,将属性从自动属性更改为只读属性public virtual IEnumerable<EventiDettaglioBeneInteressato> EventiDettaglio { get { return _eventiDettaglio; } }
    • Eventi类映射内部,将 EventiDettaglio的层叠属性更改cascade="all-delete-orphan",然后指定nhibernate,将通过后备字段而不是属性来访问包,方法是添加access="nosetter.camelcase-underscore"
    • 毕竟,需要为该类创建一个Add方法,Eventi以将子类EventiDettaglioBeneInteressato添加到该类中,在该方法内,您可以按照需要将引用父子集设置为:public virtual void Add(EventiDettaglioBeneInteressato dettaglioBeneInteressato) { dettaglioBeneInteressato.Evento = this; _eventiDettaglio.Add(dettaglioBeneInteressato); }

这些都是使您能够按需工作的所有步骤,因此,我的修改后的测试是这样的(我假设使用NUnit作为testframework,并使用FluentAssertions作为进行断言的辅助框架,但是可以轻松地更改使用MSTest的方法):

 [Test]
    public void TestMethod()
    {
        var session = SessionFactory.OpenSession();
        var codiceEvento = "20140630_013325_BA";

        //Step1. Create a new Eventi to be saved with the given code

        using (var trx = session.BeginTransaction())
        {
            var eventi = new Eventi
            {
                CodiceEvento = codiceEvento
            };
            session.SaveOrUpdate(eventi);
            trx.Commit();
        }

        //Step2. Clear the session so the Eventi object have to be loaded again
        session.Clear();
        using (var trx = session.BeginTransaction())
        {
            var evento = session.Get<Eventi>(codiceEvento);

            //assert the object has no child yet
            evento.EventiDettaglio.Count().Should().Be(0);

            //Step3. Add objects without specify the relationship
            evento.Add(new EventiDettaglioBeneInteressato
            {
                PrgOrdinamento = 1,
                CodiceTipoBeneRFI = 1
            });

            evento.Add(new EventiDettaglioBeneInteressato
            {
                PrgOrdinamento = 2,
                CodiceTipoBeneRFI = 2
            });
            evento.Add(new EventiDettaglioBeneInteressato
            {
                PrgOrdinamento = 3,
                CodiceTipoBeneRFI = 3
            });
            evento.Add(new EventiDettaglioBeneInteressato
            {
                PrgOrdinamento = 4,
                CodiceTipoBeneRFI = 4
            });

            //Step4. save the root and then check if all the collection is saved
            session.SaveOrUpdate(evento);
            trx.Commit();
        }

        //Step5. clear again the session to make sure all the things are loaded well from db
        session.Clear();
        using (var trx = session.BeginTransaction())
        {
            var evento = session.Get<Eventi>(codiceEvento);

            //Step6. load the root and then assert the child collection has 4 elements
            evento.EventiDettaglio.Count().Should().Be(4);

            //Step7. delete the root object to repeat the test again and test the cascade
            session.Delete(evento);
            trx.Commit();
        }

        //Step8. check there's no child object for that codiceEvento. the cascade is working!
        using (var trx = session.BeginTransaction())
        {
            session.Query<EventiDettaglioBeneInteressato>()
                .Count(it => it.Evento.CodiceEvento == codiceEvento)
                .Should().Be(0);

            trx.Commit();
        }

    }

只是有用,这是修改后的类和映射(修改为在您的环境之外工作):

活动课

    [Serializable]
public class Eventi
{
    private IList<EventiDettaglioBeneInteressato> _eventiDettaglio; 
    public Eventi()
    {
        _eventiDettaglio = new List<EventiDettaglioBeneInteressato>();
    }

    public virtual string CodiceEvento { get; set; }
    public virtual string DescrizioneEvento { get; set; }

    public virtual short CodiceTipoEvento { get; set; }
    public virtual short? CodiceTipoAltroEvento { get; set; }
    public virtual byte CodiceTipoClasseEvento { get; set; }
    public virtual byte? CodiceTipoCausaEvento { get; set; }
    public virtual byte CodiceTipoStatoSchedaEvento { get; set; }
    public virtual int? CodiceGestoreAsset { get; set; }
    public virtual byte? CodiceTipoOraEvento { get; set; }
    public virtual short? CodiceTipoAutoreEvento { get; set; }
    public virtual short? CodiceTipoSegnalazioneEvento { get; set; }       

    public virtual IEnumerable<EventiDettaglioBeneInteressato> EventiDettaglio { get { return _eventiDettaglio; } }

    public virtual void Add(EventiDettaglioBeneInteressato dettaglioBeneInteressato)
    {
        dettaglioBeneInteressato.Evento = this;
        _eventiDettaglio.Add(dettaglioBeneInteressato);
    }

    #region NHibernate Composite Key Requirements
    public override bool Equals(object obj)
    {
        if (obj == null) return false;
        var t = obj as Eventi;
        if (t == null) return false;
        if (CodiceEvento == t.CodiceEvento)
            return true;

        return false;
    }
    public override int GetHashCode()
    {
        int hash = GetType().GetHashCode();
        hash = (hash * 397) ^ CodiceEvento.GetHashCode();

        return hash;
    }
    #endregion
}

类映射事件

<hibernate-mapping assembly="MyOverFlow.Tests" namespace="MyOverFlow.Tests.NHibernate.Domain" xmlns="urn:nhibernate-mapping-2.2">
  <class name="Eventi" table="Eventi" lazy="true" schema="Evento">
    <id name="CodiceEvento" column="CodiceEvento" />

    <property name="CodiceTipoEvento" >
      <column name="CodiceTipoEvento" sql-type="smallint" not-null="true" />
    </property>

    <property name="CodiceTipoAltroEvento" >
      <column name="CodiceTipoAltroEvento" sql-type="smallint" not-null="false" />
    </property>

    <property name="CodiceTipoClasseEvento">
      <column name="CodiceTipoClasseEvento" sql-type="tinyint" not-null="true" />
    </property>

    <property name="CodiceTipoCausaEvento" >
      <column name="CodiceTipoCausaEvento" sql-type="tinyint" />
    </property>

    <property name="CodiceTipoStatoSchedaEvento">
      <column name="CodiceTipoStatoSchedaEvento" sql-type="tinyint" not-null="true" />
    </property>

    <property name="CodiceGestoreAsset">
      <column name="CodiceGestoreAsset" sql-type="int" not-null="false" />
    </property>

    <property name="CodiceTipoOraEvento">
      <column name="CodiceTipoOraEvento" sql-type="tinyint" not-null="false" />
    </property>

    <property name="CodiceTipoAutoreEvento">
      <column name="CodiceTipoAutoreEvento" sql-type="smallint" not-null="false" />
    </property>

    <property name="CodiceTipoSegnalazioneEvento">
      <column name="CodiceTipoSegnalazioneEvento" sql-type="smallint" not-null="false" />
    </property>

    <property name="DescrizioneEvento">
      <column name="DescrizioneEvento" sql-type="varchar" not-null="false" />
    </property>

    <bag name="EventiDettaglio" table="EventiDettaglioBeneInteressato"
         access="nosetter.camelcase-underscore"
         schema="Evento" inverse="true" cascade="all-delete-orphan" >
      <key column="CodiceEvento" />
      <one-to-many class="EventiDettaglioBeneInteressato" />
    </bag>

  </class>
</hibernate-mapping>

希望对您有所帮助!

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

NHibernate使用删除级联从父集合中删除子级

来自分类Dev

nhibernate查询Compositeid异常

来自分类Dev

NHibernate MappingByCode映射级联选项

来自分类Dev

NHibernate代理ID值

来自分类Dev

流利的NHibernate会话异常处理

来自分类Dev

NHibernate等效于<composite-index>的复合字典键的按代码映射

来自分类Dev

NHibernate多对一级联

来自分类Dev

设置NHibernate Fluent以进行级联操作。

来自分类Dev

删除级联不适用于NHibernate

来自分类Dev

nHibernate多对多和级联删除

来自分类Dev

Nhibernate所在子串错误

来自分类Dev

NHibernate ID生成-重复项

来自分类Dev

当数据库中已经存在子级时,NHibernate级联插入

来自分类Dev

视图异常之后的Nhibernate延迟加载异常

来自分类Dev

在NHibernate中从子级创建级联时,如何获得新的父级ID?

来自分类Dev

NHibernate Save正在尝试在更新时清除子KeyColumn ID

来自分类Dev

NHibernate Save正在尝试在更新时清除子KeyColumn ID

来自分类Dev

NHibernate LINQ Where和任何抛出异常

来自分类Dev

NHibernate异常破坏其他进程

来自分类Dev

NHibernate“集合映射中的重复列”异常

来自分类Dev

NHibernate抛出“无法解析属性”异常

来自分类Dev

NHibernate“在集合映射中重复的列”异常

来自分类Dev

nhibernate无法确定实体异常的类型

来自分类Dev

NHibernate条件:“ From”子句后的子查询

来自分类Dev

NHibernate SysCache不缓存子对象

来自分类Dev

NHibernate OrderBy在子对象上的投影

来自分类Dev

nhibernate与数据库上的子查询

来自分类Dev

NHibernate条件:“ From”子句后的子查询

来自分类Dev

NHibernate父级列表与子级计数