繁体   English   中英

NHibernate Composite-ID子级联异常

[英]Exception NHibernate Composite-ID Child Cascade

我在一段时间内遇到过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
    }
}

映射EventiDettaglioBeneInteressato:

<?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. 处理像您一样的子对象的双向引用集合时,如果您有一个带有孩子的根,并且每个孩子都有对其根的引用,那么通过向其中添加项来直接处理根内的子列表并不是一件好事那是因为添加子对象时,根负责设置每个子根引用。 为此,要涉及的步骤是:
    • Eventi类内添加IList<EventiDettaglioBeneInteressato>的私有字段,然后在构造函数中将其初始化为它们的新空集合
    • Eventi类内部,将EventiDettaglio属性从IList<EventiDettaglioBeneInteressato>更改为IEnumerable<EventiDettaglioBeneInteressato>
    • Eventi类内部,将属性从自动属性更改为只读属性public virtual IEnumerable<EventiDettaglioBeneInteressato> EventiDettaglio { get { return _eventiDettaglio; } } public virtual IEnumerable<EventiDettaglioBeneInteressato> EventiDettaglio { get { return _eventiDettaglio; } }
    • Eventi类映射内部,将 EventiDettaglio的层叠属性更改为cascade="all-delete-orphan" ,然后指定nhibernate,将通过后备字段而不是属性来访问包,这是通过添加access="nosetter.camelcase-underscore"
    • 毕竟,需要在Eventi类中创建一个Add方法,以将子EventiDettaglioBeneInteressato添加到该类中,该方法内部将设置您想要的引用父子项: public virtual void Add(EventiDettaglioBeneInteressato dettaglioBeneInteressato) { dettaglioBeneInteressato.Evento = this; _eventiDettaglio.Add(dettaglioBeneInteressato); } 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();
        }

    }

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

Eventi课程

    [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
}

Eventi类映射

<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>

希望有帮助!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM