NHibernate ได้อย่างคล่องแคล่ว: การละเมิดคีย์ต่างประเทศหรือค่า Null

เฮ้เพื่อนๆ ฉันมีปัญหาจริงๆ กับการทำแผนที่โดยใช้ไฮเบอร์เนตอย่างคล่องแคล่ว ฉันรู้ว่ามีโพสต์มากมายทั้งบนเว็บไซต์นี้และโพสต์อื่นๆ อีกมากมายที่เน้นไปที่การทำแผนที่ประเภทใดประเภทหนึ่งโดยเฉพาะ แต่ ณ ขณะนี้ ฉันยังไม่พบวิธีแก้ปัญหาที่สามารถแก้ไขปัญหาของฉันได้

นี่คือสิ่งที่ฉันมี:

namespace MyProject.Models.Entites
{
    public class Project
    {
       public virtual Guid Id {get; set;}
       // A load of other properties
       public virtual ProjectCatagory Catagory{get;set;}           
    }
}

แล้วแผนที่:

namespace MyProject.DataAccess.ClassMappings
{
    public class ProjectMap : ClassMap<Project>
    {
        public ProjectMap()
        {
            Id(x => x.Id);
            Map(x => x.Title);
            Map(x => x.Description);
            Map(x => x.LastUpdated);
            Map(x => x.ImageData).CustomSqlType("image");
            HasOne(x => x.Catagory);           
        }
    }
}

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

ตอนนี้เรามี:

namespace MyProject.Models.Entities
{
   public class ProjectCatagory
   {
        public virtual Guid Id { get; set; }
        public virtual String Name { get; set; }
   }
}

และแผนที่:

public ProjectCatagoryMap()
{
    Id(x => x.Id);
    Map(x => x.Name);
}

ปัญหาคือมันใช้งานไม่ได้ ! ฉันจะทำสิ่งที่คล้ายกับสิ่งต่อไปนี้ในการทดสอบหน่วย:

Project myproject = new Project("Project Description");
// set the other properties
myProject.Catagory = new ProjectCatagory(Guid.New(), "Test Catagory");
repository.Save(myProject);

ตอนนี้ฉันได้ลองใช้การกำหนดค่าการแมปและฐานข้อมูลหลายครั้งแล้วเมื่อพยายามทำให้สิ่งนี้ใช้งานได้ ขณะนี้ตารางฐานข้อมูลโครงการมีคอลัมน์ "Catagory_id" (ซึ่งฉันไม่ได้ใส่ไว้ที่นั่น ฉันคิดว่า NH เพิ่มมันเนื่องจากการแมป) และฉันจะชอบที่ตั้งค่าให้ไม่อนุญาตให้มีค่าว่าง อย่างไรก็ตาม เมื่อตั้งค่าเช่นนี้ ฉันได้รับข้อยกเว้นที่อธิบายว่าฉันไม่สามารถแทรกค่า Null ลงในตารางได้ (แม้ว่าในระหว่างการดีบัก ฉันได้ตรวจสอบคุณสมบัติทั้งหมดบนวัตถุ Project แล้วและค่าเหล่านั้นไม่ใช่ค่าว่าง)

อีกทางหนึ่ง ฉันสามารถอนุญาตให้ตารางยอมรับค่าว่างลงในคอลัมน์นั้นได้ และตารางจะบันทึกวัตถุ Project และไม่สนใจคุณสมบัติ Category โดยสิ้นเชิงเมื่อทำการบันทึก ดังนั้น เมื่อถูกดึงข้อมูล ให้ทดสอบเพื่อตรวจสอบว่าหมวดหมู่ที่ถูกต้องเชื่อมโยงกับโครงการล้มเหลวหรือไม่ .

ถ้าฉันจำไม่ผิด มีอยู่ช่วงหนึ่งที่ฉันมีการใช้ ProjectMap:

References(x => x.Catagory).Column("Catagory_id").Cascade.All().Not.Nullable();

สิ่งนี้เปลี่ยนข้อยกเว้นจาก "ไม่สามารถแทรกค่า Null" เป็นการละเมิดคีย์ต่างประเทศ

ฉันสงสัยว่าต้นตอของความยุ่งยากทั้งหมดนี้มาจากการขาดความเข้าใจในการตั้งค่าฐานข้อมูลเชิงสัมพันธ์เนื่องจากฉันมีเอนทิตีอื่น ๆ ในโครงการนี้ที่ไม่มีการพึ่งพาภายนอกซึ่งทำงานได้ดีกับ NHibernate โดยตัดปัญหาการเข้ารหัสใด ๆ ที่ฉันอาจเกิดขึ้นเมื่อ การสร้างพื้นที่เก็บข้อมูล

ความช่วยเหลือใด ๆ ที่ชื่นชมอย่างมาก ขอบคุณ


person SomeGuy    schedule 14.06.2010    source แหล่งที่มา
comment
โปรดเปลี่ยนชื่อเป็น Fluent NHibernate: ปัญหากับ HasOne เพื่อให้เจาะจงมากขึ้น   -  person Stefan Steinegger    schedule 14.06.2010


คำตอบ (3)


ปัญหาหลักที่นี่คือความเข้าใจผิดทั่วไปเกี่ยวกับความสัมพันธ์แบบ "หนึ่งต่อหนึ่ง" ในฐานข้อมูลเชิงสัมพันธ์และการแมป HasOne ใน Fluent เงื่อนไขในการแมปเป็นเงื่อนไขเชิงสัมพันธ์ (คล่องพยายามที่จะ "ตกแต่ง" พวกเขาเล็กน้อยซึ่งทำให้ IMO แย่ลง HasOne จริงๆแล้วหมายถึง: หนึ่งต่อหนึ่ง)

ดูที่ Fluent wiki:

โดยปกติ HasOne จะสงวนไว้สำหรับกรณีพิเศษ โดยทั่วไป คุณจะใช้ความสัมพันธ์อ้างอิงในสถานการณ์ส่วนใหญ่ (ดู: ฉันคิดว่าคุณหมายถึงแบบกลุ่มต่อหนึ่ง)

วิธีแก้ปัญหานั้นง่ายมาก เพียงแลกเปลี่ยน HasOne กับ References (one-to-one ถึง many-to-one ในไฟล์การแมป XML) คุณได้รับคีย์ภายนอกในฐานข้อมูลซึ่งอ้างอิงถึง ProjectCatagory


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

ในการซิงโครไนซ์คีย์หลัก คุณจะต้องเชื่อมต่อคีย์ตัวหนึ่งเข้ากับคีย์ตัวอื่น อย่างไรก็ตาม วิธีนี้ใช้ได้ผล ไม่ใช่สิ่งที่คุณต้องการที่นี่

person Stefan Steinegger    schedule 14.06.2010
comment
ฉันรู้ว่าจริง ๆ แล้ว HasOne() ผิดในข้อกำหนดเหล่านี้ แต่ดังที่ด้านล่างสุดของโพสต์บอกว่า ฉันได้ลองใช้เพียง References() แล้ว แต่มันใช้งานไม่ได้ โดยบอกว่าคำสั่ง insert ขัดแย้งกับข้อจำกัดของคีย์ต่างประเทศใน ตาราง ProjectCatagory - person SomeGuy; 14.06.2010

หลังจากลองใช้ตัวเลือกการทำแผนที่ที่มีอยู่ทั้งหมดแล้ว ฉันพบคำตอบคล้ายกับที่แนะนำ

ตามที่สงสัย HasOne() ผิดอย่างชัดเจน และ References(x => x.Catagory) เป็นส่วนหนึ่งของวิธีแก้ปัญหา อย่างไรก็ตาม ฉันยังคงได้รับข้อยกเว้นการละเมิดคีย์ต่างประเทศจนกว่า:

References(x => x.Catagory).Column("Catagory_id").Cascade.SaveUpdate().Not.Nullable().Not.LazyLoad();

แค่คิดว่า id อัปเดตเธรดในกรณีที่คนอื่นสะดุดกับปัญหาที่คล้ายกันเนื่องจากการใช้ References() ไม่ได้ผล

person SomeGuy    schedule 16.06.2010

ดูเหมือนว่าคลาส ProjectCatagory จะเป็นคลาสหลักของ Project Class ดังนั้นหากไม่มีคลาสแม่ คลาสลูกจะมีอยู่ได้อย่างไร

คุณต้องใช้-

การอ้างอิง(x => x.Catagory).Column("Catagory_id").Foreignkey("Id");

ที่นี่ Foreign Key คือรหัสตาราง ProjectCatagory ของคุณ

person ankur pancholi    schedule 06.12.2013