วิธีหลีกเลี่ยงการขึ้นต่อกันแบบวนซ้ำ (การอ้างอิงแบบวงกลม) ระหว่าง 3 ตาราง?


10

ฉันมี 3 ตาราง:

  • คน
  • เสา
  • ชอบ

เมื่อฉันออกแบบโมเดล ER มันมีการพึ่งพาแบบวนรอบ:

         1: N
คน -------- <โพสต์

         1: N
โพสต์ ---------- <ไลค์

         1: N
คน -------- <ไลค์

ตรรกะคือ:

  • 1 คนสามารถมีโพสต์ได้มากมาย

  • 1 โพสต์มีไลค์มากมาย

  • 1 คนสามารถชอบโพสต์จำนวนมาก (คนที่สร้างไม่สามารถถูกใจโพสต์ของเขาเอง)

ฉันจะลบการออกแบบแบบวงกลมนี้ได้อย่างไร หรือการออกแบบฐานข้อมูลของฉันผิด

คำตอบ:


10

กฎเกณฑ์ทางธุรกิจ

ให้เราทำ rewordings ตามกฎเกณฑ์ทางธุรกิจที่คุณนำเสนอ:

  • Personสร้างศูนย์หนึ่งหรือหลาย Posts
  • Postได้รับเป็นศูนย์หนึ่งหรือหลาย Likes
  • Personปรากฏเป็นศูนย์หนึ่งหรือหลาย Likes , แต่ละชเกี่ยวข้องกับการหนึ่งที่เฉพาะเจาะจง Post

โมเดลเชิงตรรกะ

จากนั้นจากชุดดังกล่าวยืนยันผมได้มาสองระดับตรรกะIDEF1X [1]รูปแบบข้อมูลที่แสดงในรูปที่ 1

รูปที่ 1 - โมเดลข้อมูลบุคคลและโพสต์

ตัวเลือก A

ที่คุณสามารถดูในรูปแบบที่เป็นตัวเลือกที่PersonId อพยพ[2]จากPersonการPostเป็นสำคัญต่างประเทศ (FK) แต่มันได้รับชื่อบทบาท[3]ของAuthorIdและแอตทริบิวต์นี้ทำให้ขึ้นพร้อมกับPostNumberคีย์หลัก (PK) ของPostประเภทกิจการ

ผมคิดว่าLikeสามารถที่มีอยู่ในการเชื่อมต่อกับโดยเฉพาะอย่างยิ่งPostเพื่อให้ฉันได้ตั้งค่าLikePK ที่ประกอบด้วยสามคุณลักษณะที่แตกต่างกันPostAuthorId, และPostNumber LikerIdการรวมกันของPostAuthorIdและPostNumberเป็น FK ที่ทำให้การอ้างอิงที่เหมาะสมกับPostPK LikerIdคือในการเปิด FK Person.PersonIdที่สร้างความสัมพันธ์ที่เหมาะสมกับ

ด้วยความช่วยเหลือของโครงสร้างนี้คุณมั่นใจได้ว่าบุคคลที่กำหนดสามารถปรากฏLikeเหตุการณ์เดียวกับPostอินสแตนซ์เดียวกันเท่านั้น

วิธีการเพื่อป้องกันไม่ให้ผู้เขียนโพสต์โดนใจโพสต์ของเขาเอง

เนื่องจากคุณไม่ต้องการให้ความเป็นไปได้ที่บุคคลสามารถชอบโพสต์ที่ผู้แต่งสร้างขึ้นเมื่ออยู่ในช่วงการนำไปใช้งานคุณควรกำหนดวิธีการเปรียบเทียบค่าของLike.PostAuthorIdกับค่าของLike.LikerIdในทุกครั้งที่พยายามแทรก หากค่าดังกล่าวตรงกัน(a)คุณปฏิเสธการแทรกหากค่าเหล่านั้นไม่ตรงกัน(b)คุณปล่อยให้กระบวนการดำเนินการต่อ

ในการทำภารกิจนี้ให้สำเร็จในฐานข้อมูลของคุณคุณสามารถใช้:

  1. ตรวจสอบข้อ จำกัดแต่แน่นอนวิธีนี้ไม่รวม MySQL เพราะมันยังไม่ได้รับการดำเนินการในแพลตฟอร์มนี้เพื่อให้ห่างไกลที่คุณสามารถดูที่นี่และที่นี่

  2. สายรหัสภายในACID การทำธุรกรรม

  3. บรรทัดโค้ดภายในTRIGGERซึ่งสามารถส่งคืนข้อความที่กำหนดเองซึ่งระบุถึงความพยายามละเมิดกฎ

ตัวเลือก B

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

วิธีการนี้ยังช่วยให้แน่ใจว่าโพสต์สามารถถูกใจโดยคนคนเดียวกันเพียงครั้งเดียว


หมายเหตุ

1. Integration Definition สำหรับการสร้างแบบจำลองข้อมูล ( IDEF1X ) เป็นเทคนิคการสร้างแบบจำลองข้อมูลที่ขอแนะนำอย่างมากซึ่งถูกกำหนดให้เป็นมาตรฐานในเดือนธันวาคม 1993 โดยสถาบันมาตรฐานและเทคโนโลยีแห่งชาติของสหรัฐอเมริกา ( NIST )

2. IDEF1X กำหนดการโอนย้ายคีย์เป็น“ กระบวนการสร้างโมเดลของการวางคีย์หลักของพาเรนต์หรือเอนทิตีทั่วไปในเอนทิตีย่อยหรือหมวดหมู่เป็นคีย์ต่างประเทศ "

3. ชื่อบทบาทคือ denotation ที่กำหนดให้กับแอตทริบิวต์ foreign key เพื่อแสดงความหมายของแอตทริบิวต์ดังกล่าวในบริบทของประเภทเอนทิตีที่เกี่ยวข้อง บทบาทการตั้งชื่อจะแนะนำตั้งแต่ปี 1970 โดยดร. EF Coddในกระดาษน้ำเชื้อของเขาที่ชื่อ“เป็นเชิงรูปแบบของข้อมูลขนาดใหญ่ที่ใช้ร่วมกันข้อมูลธนาคาร” สำหรับส่วนของมัน IDEF1X - ความซื่อสัตย์เกี่ยวกับการปฏิบัติที่เกี่ยวข้อง -ยังสนับสนุนขั้นตอนนี้


6

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

  • บุคคลสามารถเขียนบทความได้หลายโพสต์เขียนโดยคนคนเดียว: 1:n
  • คนสามารถชอบโพสต์ได้หลายคนหลายคนชอบโพสต์n:m
    : ความสัมพันธ์ n: m สามารถนำไปใช้กับความสัมพันธ์อื่น: likes.

การใช้งานขั้นพื้นฐาน

การใช้งานพื้นฐานอาจมีลักษณะเช่นนี้ในPostgreSQL :

CREATE TABLE person (
  person_id serial PRIMARY KEY
, person    text NOT NULL
);

CREATE TABLE post (
  post_id   serial PRIMARY KEY
, author_id int NOT NULL  -- cannot be anonymous
     REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE  -- 1:n relationship
, post      text NOT NULL
);

CREATE TABLE likes (  -- n:m relationship
  person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE
, post_id   int REFERENCES post ON UPDATE CASCADE ON DELETE CASCADE
, PRIMARY KEY (post_id, person_id)
);

โปรดทราบว่าโพสต์ต้องมีผู้แต่ง ( NOT NULL) ในขณะที่มีไลค์อยู่เป็นตัวเลือก สำหรับการกดไลค์ที่มีอยู่แล้วpostและperson ต้องอ้างอิงทั้งคู่ (บังคับโดยให้การPRIMARY KEYทำให้ทั้งสองคอลัมน์NOT NULLโดยอัตโนมัติ (คุณอาจเพิ่มข้อ จำกัด เหล่านี้อย่างชัดเจนซ้ำซ้อน) เพื่อให้ไลค์ที่ไม่ระบุชื่อเป็นไปไม่ได้

รายละเอียดสำหรับการใช้งาน n: m:

ป้องกันตนเองเหมือน

คุณยังเขียนว่า:

(คนที่สร้างขึ้นไม่สามารถชอบโพสต์ของเขาเอง)

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

หินแข็งสำหรับค่าใช้จ่าย

หากจะต้องมีหินแข็งคุณสามารถขยาย FK จากlikesการpostรวมauthor_idเกินความจำเป็น จากนั้นคุณสามารถแยกแยะการร่วมประเวณีระหว่างพี่น้องด้วยCHECKข้อ จำกัดง่ายๆ

CREATE TABLE likes (
  person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE
, post_id   int 
, author_id int NOT NULL
, CONSTRAINT likes_pkey PRIMARY KEY (post_id, person_id)
, CONSTRAINT likes_post_fkey FOREIGN KEY (author_id, post_id)
     REFERENCES post(author_id, post_id) ON UPDATE CASCADE ON DELETE CASCADE
, CONSTRAINT no_self_like CHECK (person_id <> author_id)
);

สิ่งนี้ต้องมีUNIQUEข้อ จำกัดอย่างอื่นที่ซ้ำซ้อนในpost:

ALTER TABLE post ADD CONSTRAINT post_for_fk_uni UNIQUE (author_id, post_id);

ฉันใส่author_idก่อนเพื่อให้ดัชนีที่มีประโยชน์ในขณะที่อยู่ที่มัน

คำตอบที่เกี่ยวข้องมีมากขึ้น:

ถูกกว่าด้วยCHECKข้อ จำกัด

สร้างใน "การใช้งานขั้นพื้นฐาน" ด้านบน

CHECKข้อ จำกัด หมายถึงการไม่เปลี่ยนรูป การอ้างอิงตารางอื่น ๆ สำหรับการตรวจสอบนั้นไม่มีวันเปลี่ยนแปลงเลย ฉันขอแนะนำให้ประกาศข้อ จำกัดNOT VALIDเพื่อสะท้อนให้เห็นอย่างถูกต้อง รายละเอียด:

CHECKจำกัด ดูเหมือนว่าเหมาะสมในกรณีนี้โดยเฉพาะอย่างยิ่งเพราะผู้เขียนโพสต์ดูเหมือนว่าแอตทริบิวต์ที่ไม่เคยเปลี่ยนแปลง ไม่อนุญาตให้อัปเดตฟิลด์นั้น ๆ เพื่อให้แน่ใจ

เราปลอมIMMUTABLEฟังก์ชั่น:

CREATE OR REPLACE FUNCTION f_author_id_of_post(_post_id int)
  RETURNS int AS
'SELECT p.author_id FROM public.post p WHERE p.post_id = $1'
LANGUAGE sql IMMUTABLE;

แทนที่ 'สาธารณะ' ด้วยสคีมาที่แท้จริงของตารางของคุณ
ใช้ฟังก์ชันนี้ในCHECKข้อ จำกัด :

ALTER TABLE likes ADD CONSTRAINT no_self_like_chk
   CHECK (f_author_id_of_post(post_id) <> person_id) NOT VALID;

4

ฉันคิดว่าคุณกำลังมีปัญหาในการหาสิ่งนี้เนื่องจากวิธีที่คุณระบุกฎเกณฑ์ทางธุรกิจของคุณ

ผู้คนและโพสต์คือ "วัตถุ" ไลค์คือกริยา

คุณมีการกระทำ 2 รายการจริงๆ:

  1. บุคคลสามารถสร้างหนึ่งโพสต์ขึ้นไป
  2. หลายคนสามารถชอบโพสต์มากมาย (การรวบรวมคำสั่ง 2 รายการสุดท้ายของคุณ)

คนชอบโพสต์แผนภาพ

ตาราง "ไลค์" จะมี person_id และ post_id เป็นคีย์หลัก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.