NHibernate ไม่เรียกใช้คำสั่งอัปเดตขณะแก้ไขเอนทิตีที่มีอยู่

ฉันกำลังใช้ NHibernate & Net Persistence API กับ C# และ MySql db ในโปรเจ็กต์ของฉัน และฉันมีเลเยอร์ UI (ASP.NET), Business Layer และ Data Access Layer (DAL) ฉันมีวิธีบันทึกต่อไปนี้ในคลาส UserManager ของ DAL:

        private EntityManager GetEm()
        {
            if (_entityManager == null)
            {
                _entityManagerFactory = Persistence.CreateEntityManagerFactory("JPUMain");
                _entityManager = _entityManagerFactory.CreateEntityManager();
            }
            return _entityManager;
        }

        public void **Save**(IGenericEntity entity)
        {
            _entityManager = GetEm();
            _entityManager.GetTransaction().Begin();
            _entityManager.Persist(entity);
            _entityManager.Flush();            
            _entityManager.GetTransaction().Commit();            
            _entityManager.Clear();
        }

เอนทิตีผู้ใช้ของฉัน:

 [Entity]
 [Table(Name = "user")]
 public class User : IGenericEntity
    {
        [Id]
        [GeneratedValue]
        public virtual int ID { get; set; }

        [Basic]
        [Column(Name = "fname", Nullable = false)]
        public virtual string FirstName { get; set; }

        [Basic]
        [Column(Name = "lname", Nullable = false)]
        public virtual string LastName { get; set; 
    }

ตอนนี้ถ้าฉันพยายามบันทึกผู้ใช้ด้วยการโทร:

UserManager.save(user)

จากนั้นจะบันทึกรายการลงใน db อย่างถูกต้อง แต่พูดในครั้งถัดไป (เวลาใดก็ได้ ไม่ใช่ในเซสชันเดียวกัน) หากฉันพยายามแก้ไขรายละเอียดผู้ใช้ แทนที่จะเรียกใช้คำสั่ง update มันจะเรียกใช้งาน insert และแทรกบันทึกใหม่ด้วยเอนทิตีผู้ใช้ที่แก้ไข ฉันกำลังตั้งค่าคีย์หลักของผู้ใช้อย่างถูกต้องให้กับวัตถุที่แก้ไข

นอกจากนี้ เมื่อฉันเรียกใช้กรณีทดสอบสำหรับสิ่งเดียวกันโดยใช้ NUnit มันจะพิมพ์บรรทัดต่อไปนี้:

NHibernate: SELECT LAST_INSERT_ID()
NHibernate: INSERT INTO user (uid, fname, lname) VALUES (?p0, ?p1, ?p2);?p0 = 2[Type: Int32 (0)], ?p1 = 'First Name' [Type: String (9)], ?p2 = 'Last Name' [Type: String (9)]

ฉันลองใช้คำสั่งนี้โดยตรงจาก phpmyadmin ในตารางผู้ใช้ และมันจะให้ค่าเป็น 0 เสมอ ฉันกำลังใช้เครื่องมือ InnoDB

ใครช่วยบอกฉันหน่อยได้ไหมว่าเหตุใดจึงไม่อัปเดตเอนทิตีผู้ใช้ที่มีอยู่ และกำลังสร้างบันทึกใหม่ด้วยเอนทิตีที่แก้ไขแทน


person Arry    schedule 06.01.2013    source แหล่งที่มา


คำตอบ (2)


คุณกำลังบันทึกเอนทิตีใน ISession อื่นที่ไม่ใช่ ISession ที่คุณใช้เพื่อดึงข้อมูลเอนทิตี

สิ่งที่ดีที่สุดที่คุณสามารถทำได้คือตรวจสอบให้แน่ใจว่าคุณใช้ ISession เดียวกัน ฉันคิดว่าคุณควรคิดจริงๆ ว่าคุณจะจัดการเรื่องนั้นอย่างไร เซสชันควรมีอายุการใช้งานสั้น ดังนั้นสิ่งที่ดีที่สุดคือการสร้างชั้นบริการบางประเภทที่จัดการกรณีการใช้งานที่แตกต่างกัน

person Frederik Gheysels    schedule 06.01.2013
comment
แม้ว่าฉันกำลังสร้างเอนทิตีใหม่ และแก้ไขเอนทิตีในตอนนั้นและที่นั่น (ภายในวิธีการสร้างเอนทิตีเดียวกัน) โดยใช้เซสชันเดียวกัน มันจะแทรกเรกคอร์ดใหม่แทนที่จะแก้ไขที่มีอยู่ - person Arry; 07.01.2013
comment
คุณสามารถโพสต์รหัสเพิ่มเติมได้หรือไม่? กรณีที่คุณใช้เซสชันเดียวกันและได้รับการแทรกสองครั้ง? (รวมถึงวิธีการจัดการเอนทิตี) - person pkmiec; 07.01.2013

Persist ไม่เคยทำการอัปเดต

เมื่อเจาะลึกแหล่งที่มาของ NH คุณอาจเห็นว่า Persist ซึ่งมีการใช้งานจริงใน DefaultPersistEventListener ตรวจสอบสถานะของเอนทิตี:

public class DefaultPersistEventListener : AbstractSaveEventListener, IPersistEventListener
{
    //..
    public virtual void OnPersist(PersistEvent @event, IDictionary createdAlready)
    {
        //... 
        EntityState entityState = GetEntityState(entity, @event.EntityName, source.PersistenceContext.GetEntry(entity), source);

        switch (entityState)
        {
            case EntityState.Persistent:
                EntityIsPersistent(@event, createdAlready);
                break;
            case EntityState.Transient:
                EntityIsTransient(@event, createdAlready);
                break;
            case EntityState.Detached:
                throw new PersistentObjectException("detached entity passed to persist: " + GetLoggableName(@event.EntityName, entity));
            default:
                throw new ObjectDeletedException("deleted instance passed to merge", null, GetLoggableName(@event.EntityName, entity));
        }

}

วิธีเดียวที่ EntityIsTransient ส่งส่วนแทรกไปยังฐานข้อมูล ดังนั้นในบริบทของเซสชันที่คุณกำลังอัปเดต เอนทิตีที่เป็นปัญหาจึงเป็นแบบชั่วคราว คุณควรโหลดหรือแนบเอนทิตีนี้กับบริบทของเซสชันก่อนที่จะทำการฟลัช วิธี SaveOrUpdate อาจเป็นทางลัดที่มีประโยชน์

person pkmiec    schedule 06.01.2013
comment
คุณช่วยยกตัวอย่างเกี่ยวกับวิธีการแนบเอนทิตีเข้ากับบริบทของเซสชันก่อนที่จะทำการฟลัชได้หรือไม่? ขอบคุณสำหรับคำตอบ! - person Arry; 07.01.2013
comment
นอกจากนี้ Dooh ฉันกำลังใช้ NPersistence (การนำ NHibernate ไปใช้) และฉันไม่เห็นวิธี SaveOrUpdate ใด ๆ ที่นี่ ... ฉันจะบรรลุเป้าหมายนี้ใน NPersitence ได้อย่างไร - person Arry; 07.01.2013