【问题标题】:Nhibernate many-to-many with extra column,Nhibernate 多对多与额外的列,
【发布时间】:2012-07-31 08:48:12
【问题描述】:

我对 NHibernate 有点陌生。我希望使用 C# 使用 asp.net 实现一个 Web 应用程序。

我有以下数据库架构:

Database Schemas

这是我的 NHibernate 映射文件。我不确定我的映射是否正确。如果我做错了,请纠正我。

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="TelDir.Core.Domain.Status, TelDir.Core" table="tblStatus" lazy="false">
    <id name="ID" column="StatusID" unsaved-value="0">
      <generator class="identity" />
    </id>

    <property name="StatusCode" column="StatusCode" />
    <property name="StatusName" column="StatusName" />

    <!--
    <set name="WorkOrderStatus" table="tblWorkOrderStatus" inverse="true">
      <key column="StatusID" />
      <one-to-many class="TelDir.Core.Domain.WorkOrderStatus, TelDir.Core" />
    </set>
    -->
  </class>

</hibernate-mapping>



<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="TelDir.Core.Domain.WorkOrder, TelDir.Core" table="tblWorkOrder" lazy="false">
    <id name="ID" column="WOID" unsaved-value="0">
      <generator class="identity" />
    </id>
    <property name="WorkOrderRef" column="WORef" />
    <property name="WorkOrderDesc" column="WODesc" />


    <set name="WorkOrderStatus" table="tblWorkOrderStatus" inverse="true">
      <key column="WOID" />
      <one-to-many class="TelDir.Core.Domain.WorkOrderStatus, TelDir.Core" />
    </set>

  </class>
</hibernate-mapping>



<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="TelDir.Core.Domain.WorkOrderStatus, TelDir.Core" table="tblWorkOrderStatus" lazy="false">
    <composite-id>
      <key-many-to-one name="WorkOrder" column="WOID"/>
      <key-many-to-one name="Status" column="StatusID"/>
    </composite-id>
    <property name="LastModifyDateTime" column="LastModifiedOn"  type="Timestamp" />
    <property name="CreatedBy" column="CreatedBy" />
  </class>
</hibernate-mapping>  

我的 POCO 课程如下所示

public class Status : DomainObject<Int16>
    {
        private string _statuscode = "";
        private string _statusname = "";
        //private ISet<WorkOrderStatus> _workorder_status = new HashedSet<WorkOrderStatus>()  ;

        public Status() { }

        public Status(string statusCode, string statusName) {
            this._statuscode = statusCode;
            this._statusname = statusName; 
        }

        public string StatusCode        {
            get { return _statuscode ; }
            set { _statuscode  = value; }
        }

        public string StatusName
        {
            get { return _statusname; }
            set { _statusname = value; }
        }

        /*
        public ISet<WorkOrderStatus> WorkOrderStatus
        {
            get { return (_workorder_status); }
            protected set { _workorder_status = value; }
        }
        */
    }



  public class WorkOrder : DomainObject<long>
    {
        private string _workorder_ref = "";
        private string _workorder_desc = "";
        private ISet<WorkOrderStatus> _workorder_status = new HashedSet<WorkOrderStatus>();

        public WorkOrder() { }

        public WorkOrder(string wref, string wdecs) {
            this._workorder_ref = wref;
            this._workorder_desc = wdecs;
        }

        public string WorkOrderRef   {
            get { return _workorder_ref ; }
            set { _workorder_ref = value; }
        }

        public string WorkOrderDesc
        {
            get { return _workorder_desc; }
            set { _workorder_desc = value; }
        }


        public ISet<WorkOrderStatus> WorkOrderStatus
        {
            get { return (_workorder_status); }
            protected set { _workorder_status = value; }
        }


        public void AddStatus(Status st, DateTime dt)
        {
                WorkOrderStatus obj = new WorkOrderStatus();
                obj.WorkOrder = this;
                obj.Status = st;
                obj.LastModifyDateTime = dt;
                _workorder_status.Add(obj);
        }
    }


    public class WorkOrderStatus 
    {
        private DateTime _lastmodifydt;
        private WorkOrder _workorder;
        private Status _status;
        private int _createdby;

        public WorkOrderStatus() { 
        }



        public DateTime LastModifyDateTime{ 
            get { return _lastmodifydt; }
            set { _lastmodifydt = value; }
        }

        public WorkOrder WorkOrder
        {
            get { return _workorder; }
            set { _workorder = value; }
        }
        public Status  Status
        {
            get { return _status; }
            set { _status = value; }
        }

        public int CreatedBy {
            get { return _createdby; }
            set { _createdby = value; }
        }


        public override bool Equals(object other)
        {

            //if (this == other) return true;

            //WorkOrderStatus obj = other as WorkOrderStatus;
            //if (obj == null) return false; // null or not a cat

            //if (_lastmodifydt != obj._lastmodifydt ) return false;            

            //return true;


            if (other == null)
                return false;
            WorkOrderStatus t = other as WorkOrderStatus;
            if (t == null)
                return false;
            if (WorkOrder  == t.WorkOrder  && Status  == t.Status && _lastmodifydt == t.LastModifyDateTime )
                return true;
            return false;  
        }

        public override int GetHashCode()
        {

            unchecked
            {
                int result;
                result = _lastmodifydt.GetHashCode();
                result = 29 * result + WorkOrder.GetHashCode() + Status.GetHashCode();
                return result;
            }

            //return (WorkOrder.ID + "|" + Status.ID + "|" + Status.StatusName).GetHashCode();  
        }

    }

我希望我的数据出现在这样的表格中:

[tblWorkOrderStatus]

 StatusID           WOID              LastModifiedOn              CreatedBy
 --------------------------------------------------------------------------
 2                  1                 06/20/2012 09:45:40.209         1  

[tblWorkOrder]

 WOID               WORef             WODesc
 -------------------------------------------
   1                001               Test-001 

[tbl状态]

 StatusID           StatusCode        StatusName
 -----------------------------------------------
   1                'X001'            OPEN
   2                'X002'            CLOSE

如何将记录添加到 [tblWorkOrderStatus]?

我已经编写了如下测试代码,但是我发现关联表[tblWorkOrderStatus]中没有添加记录,我不知道为什么它没有添加。

           WorkOrder Wo = new WorkOrder('001', 'Test-001');
           daoFactory.GetWorkOrderDao().Save(Wo);

           Status St = daoFactory.GetStatusDao().GetById(1, false);

                //// Secode Methode
                WorkOrderStatus _objWS = new WorkOrderStatus();
                _objWS.WorkOrder      = Wo;
                _objWS.Status     = St;
                _objWS.LastModifyDateTime = DateTime.Now;
                _objWS.CreatedBy = 1; //suppose 1 is current login UserID 

                Wo.WorkOrderStatus.Add(_objWS);

          daoFactory.GetWorkOrderDao().Save(Wo);

我可能在 POCO、NHibernate 映射文件或其他地方遗漏了一些东西。您能否指导我找到正确的解决方案?

最好的问候,

这是我的堆栈跟踪:

"   at System.ThrowHelper.ThrowKeyNotFoundException()\r\n   
at System.Collections.Generic.Dictionary`2.get_Item(TKey key)\r\n   
at NHibernate.Engine.StatefulPersistenceContext.RemoveEntity(EntityKey key)\r\n   
at NHibernate.Action.EntityDeleteAction.Execute()\r\n   
at NHibernate.Engine.ActionQueue.Execute(IExecutable executable)\r\n   
at NHibernate.Engine.ActionQueue.ExecuteActions(IList list)\r\n   
at NHibernate.Engine.ActionQueue.ExecuteActions()\r\n   
at NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session)\r\n   
at NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event)\r\n   
at NHibernate.Impl.SessionImpl.Flush()\r\n   
at NHibernate.Transaction.AdoTransaction.Commit()\r\n   
at TelDir.Data.NHibernateSessionManager.CommitTransaction() 
in E:\\OLD PC\\D\\WORKS\\PROJECT\\TelDIR\\Data\\NHibernateSessionManager.cs:line 120\r\n   
at TelDir.Web.NHibernateSessionModule.CommitAndCloseSession(Object sender, EventArgs e) 
in e:\\OLD PC\\D\\WORKS\\PROJECT\\TelDIR\\Web\\App_Code\\NHibernateSessionModule.cs:line 38\r\n   
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()\r\n   
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)"

【问题讨论】:

    标签: nhibernate many-to-many


    【解决方案1】:

    主要问题是WorkOrder.WorkOrderStatus 上没有级联,因此 NHibernate 不会知道在您保存时保留它在该集合中找到的更改。

    我更改了WorkOrder.hbm.xml,所以set 看起来像这样:

    <set name="WorkOrderStatus" table="tblWorkOrderStatus" inverse="true"  cascade="all-delete-orphan">
      <key column="StatusID" />
      <one-to-many class="TelDir.Core.Domain.WorkOrderStatus, TelDir.Core" />
    </set>
    

    然后这个测试通过了:

        // Arrange
        var workorder = new WorkOrder("001", "Test-001");
        var status = new Status("1", "Status-1");
    
        workorder.AddStatus(status, DateTime.Now);
    
        WorkOrderStatus expected;
    
        // Act
        using (ISession session = _factory.OpenSession())
        using (ITransaction tx = session.BeginTransaction())
        {
            session.Save(status);
            session.SaveOrUpdate(workorder);
    
            tx.Commit();
        }
    
        using (ISession session = _factory.OpenSession())
        using (ITransaction tx = session.BeginTransaction())
        {
            expected = session.Query<WorkOrderStatus>()
                .Fetch(s => s.Status)
                .Fetch(s => s.WorkOrder)
                .FirstOrDefault();
        }
    
        // Assert
        expected.Should().NotBeNull();
        expected.Status.Should().Be(status);
        expected.WorkOrder.Should().Be(workorder);
    

    删除

    取消注释Status 上的ISet&lt;WorkOrderStatus&gt; WorkOrderStatus 属性。此外,在 Status.hbm.xml 中取消注释 &lt;set name="WorkOrderStatus" ...,并像在 WorkOrder 上一样添加属性 cascade="all-delete-orphan"

    添加到工作订单:

    public void RemoveStatus(WorkOrderStatus item)
    {
        if (!WorkOrderStatus.Contains(item)) return;
    
        item.Status.WorkOrderStatus.Remove(item);
        WorkOrderStatus.Remove(item);
    }
    

    现在,这个测试应该通过了:

        // Arrange
        var workorder = new WorkOrder("001", "Test-001");
        var status = new Status("1", "Status-1");
    
        workorder.AddStatus(status, DateTime.Now);
    
        WorkOrderStatus expected;
    
        // Act
        using (ISession session = _factory.OpenSession())
        using (ITransaction tx = session.BeginTransaction())
        {
            session.Save(status);
            session.SaveOrUpdate(workorder);
    
            tx.Commit();
        }
    
        using (ISession session = _factory.OpenSession())
        using (ITransaction tx = session.BeginTransaction())
        {
            expected = session.Query<WorkOrderStatus>()
                .Fetch(s => s.Status)
                .Fetch(s => s.WorkOrder)
                .FirstOrDefault();
    
            expected.WorkOrder.RemoveStatus(expected);
    
            tx.Commit();
        }
    
        using (ISession session = _factory.OpenSession())
        using (ITransaction tx = session.BeginTransaction())
        {
            expected = session.Query<WorkOrderStatus>()
                .Fetch(s => s.Status)
                .Fetch(s => s.WorkOrder)
                .FirstOrDefault();
        }
    
        // Assert
        expected.Should().BeNull();
    

    【讨论】:

    • WorkOrder.hbm.xml中&lt;set name="WorkOrderStatus" table="tblWorkOrderStatus" inverse="true" cascade="all-delete-orphan"&gt; &lt;key column="StatusID" /&gt; &lt;one-to-many class="TelDir.Core.Domain.WorkOrderStatus, TelDir.Core" /&gt; &lt;/set&gt;&lt;set name="WorkOrderStatus" table="tblWorkOrderStatus" inverse="true" cascade="all-delete-orphan"&gt; &lt;key column="WOID" /&gt; &lt;one-to-many class="TelDir.Core.Domain.WorkOrderStatus, TelDir.Core" /&gt; &lt;/set&gt;有什么不同?
    • 如何从关联表 [tblWorkOrderStatus] 中删除数据。我想删除当前添加的记录。我该怎么办?我尝试使用 WorkOrderStatus obj = new WorkOrderStatus(); obj.WorkOrder = 这个; obj.状态 = st; obj.LastModifyDateTime = dt; obj.CreatedBy = 用户 ID; _workorder_status.Remove(obj);但没有运气删除。
    • 我更改了cascade="all-delete-orphan"。我已编辑我的答案以反映删除项目。
    • 运行从关联表中删除数据的脚本后出现此错误:{“字典中不存在给定的键。”}
    • 我没有收到同样的错误,但我肯定遇到了错误。首先,我的删除测试有一些错误。其次,主要问题是RemoveStatus 在做item.WorkOrder = null; item.Status = null;。只需删除这两行。我已更新我的答案以反映这些变化。
    猜你喜欢
    • 2014-04-29
    • 1970-01-01
    • 2017-12-23
    • 2012-10-31
    • 2016-05-11
    • 1970-01-01
    • 2014-09-30
    • 2018-07-19
    • 1970-01-01
    相关资源
    最近更新 更多