Nhibernate Multiple table มีความสัมพันธ์แบบหนึ่งต่อหลายตารางกับตารางเฉพาะ

ฉันมีตาราง เรียก A กันดีกว่า A มีช่อง - objId

มีตารางอื่นๆ ให้เรียก B, C และ D ซึ่งมีรายการระเบียน A จำเป็นต้องสร้างบันทึกโดยการเพิ่มบันทึก A ลงในรายการบันทึก A ของหนึ่งในตาราง B, C และ D ฟิลด์ objId จะต้องเป็น PK (id) ของบันทึก B/C/D ใครมีรายการ ของ A.

ซึ่งหมายความว่า - objId คือ FK สำหรับหลาย ๆ ตาราง ฉันเริ่มต้นด้วยตาราง B แต่หลังจากที่ตาราง B สร้างฟิลด์ objId ของตาราง A ที่สร้างขึ้น และตอนนี้จะเป็นอย่างไรกับโต๊ะ C และ D? พวกเขาไม่สามารถสร้างคอลัมน์ objId ในตารางได้

รหัสคือ:

<id name="Id">
  <generator class="guid" />
</id>

<bag name="As" cascade="All">
  <key column="ObjId" />
  <one-to-many class="A" />
</bag>

<class name="A">
<id name="Id">
  <generator class="guid" />
</id>
<property name="ObjId" />

public class B
{
    public virtual Guid Id { get; set; }
    public virtual IList<A> As{ get; set; }
}

public class A
{  
    public virtual Guid Id { get; set; }
    public virtual string ObjId { get; set; }
}

เพิ่มบันทึก A ให้กับ B:

       this.Update(session =>
       {
           var bRecord = ....;

           bRecord.As.Add(new ARecord {
                 ...
          });

             session.Update(bRecord);
       });

ฉันจะต้องสร้างการเชื่อมโยงที่ถูกต้องได้อย่างไร?


person Shir    schedule 20.03.2014    source แหล่งที่มา


คำตอบ (1)


โดยทั่วไปมีวิธีจัดการกับสถานการณ์นี้หลายวิธี - แต่ละวิธีจะต้องมีการปรับเปลี่ยน/ขยายออกไป เช่น. คุณต้องเปลี่ยนโครงสร้างฐานข้อมูลของคุณต่อไป

หากอินสแตนซ์ของ A สามารถอ้างอิงได้โดย B, C, D แต่ละตัว วิธีเดียวที่จะแนะนำคอลัมน์คีย์นอก BObjectId, CObjectId, DObjectId

หากอินสแตนซ์ของ A สามารถใช้ได้โดยหนึ่งในนั้น (B, C, D) เราจำเป็นต้องมีคอลัมน์ใหม่ ลองเรียกมันว่า Discriminator

<class name="A">
  <id name="Id" generator="guid" />
 <property name="ObjId" />
 <property name="Discriminator" />
</class>

ตอนนี้เราต้องกรอกค่าลงใน Discriminator ในโค้ด C# ของเราให้ถูกต้อง ถ้า A ถูกกำหนดให้กับ B เราจะต้องกรอก 'B'

var a = new A();
b.AddA(a);

โดยที่การดำเนินการควรจะเป็นเช่นนี้

public virtual void AddA(A a)
{
    As.Add(a);
    a.ObjectId = this.ID
    a.Discriminator = 'B'
}

หมายเหตุ: ในกรณีนี้ เราจะกำหนด ID ให้กับ ObjectId มันใช้งานได้ แต่เฉพาะเมื่อมีการกำหนด ID แล้วเท่านั้น มันจะไม่ทำงานหากวัตถุ B เป็นแบบชั่วคราว โดยมีค่า ID เริ่มต้น ในกรณีนั้นเราจะต้องสร้างวิธีแก้ปัญหาบางอย่าง เช่น. Flush() the B จากนั้นกำหนดการอ้างอิง...

ดังนั้นเราจึงประสบความสำเร็จในการจัดการ/กรอก/แทรกค่า Discriminator ลงในอินสแตนซ์/บันทึก A ได้อย่างถูกต้อง ตอนนี้เราสามารถใช้มันสำหรับ การทำแผนที่ ได้ด้วย การทำแผนที่ถุง B, C, D จะคล้ายกันมาก:

<class name="A">
  <bag name="As" cascade="All" batch-size="25"
    where=" Discriminator = 'B' " >
      <key column="ObjId" />
      <one-to-many class="A" />
  </bag>

where=" Discriminator = 'B' " เป็นวิธีที่ดีในการฉีดตัวกรองของ NHibernate ลงในคอลเลกชันของเรา ใช้แบบเดียวกันกับ C, D... และ ...

person Radim Köhler    schedule 21.03.2014
comment
ขอบคุณมากสำหรับความช่วยเหลือของคุณ. ดังที่คุณกล่าวไว้ว่า 'โดยทั่วไปแล้วมีวิธีจัดการกับสถานการณ์นี้มากกว่านั้น' พวกเขาคืออะไร? วิธีที่คุณเขียนเป็นวิธีที่ดีที่สุดหรือไม่? - person Shir; 24.03.2014
comment
เยี่ยมมากถ้ามันช่วยได้ เพลิดเพลินไปกับ NHiberante ;) - person Radim Köhler; 24.03.2014