สมาชิก: ใช้ ID ที่ไม่ซ้ำกับวัตถุโดเมน


10

หลังจากคำตอบที่มีประโยชน์สองสามข้อว่าฉันควรใช้วัตถุโดเมนหรือรหัสที่ไม่ซ้ำกันเป็นพารามิเตอร์วิธีการ / ฟังก์ชั่นที่นี่ตัวบ่งชี้ vs วัตถุโดเมนเป็นพารามิเตอร์วิธีฉันมีคำถามที่คล้ายกันอีกสมาชิก: (การอภิปรายคำถามก่อนหน้านี้ไม่ได้จัดการ ครอบคลุมสิ่งนี้) ข้อดีและข้อเสียของการใช้ ID ที่ไม่ซ้ำกันในฐานะสมาชิก vs object เป็นสมาชิกคืออะไร ฉันกำลังขอให้อ้างอิงกับภาษาที่พิมพ์อย่างมากเช่น Scala / C # / Java ฉันควรจะมี (1)

User( id: Int, CurrentlyReadingBooksId: List[Int])
Book( id: Int, LoanedToId: Int )

หรือ (2) เป็นที่ต้องการสำหรับ (1) หลังจากผ่าน: เราควรกำหนดประเภทสำหรับทุกสิ่งหรือไม่

User( id: UserId, CurrentlyReadingBooksId: List[ BookId] )
Book( id: BookId, LoanedToId: UserId )

หรือ (3)

User( id: Int, CurrentlyReadingBooks: List[Book]) 
Book( id: Int, LoanedTo: User)

ในขณะที่ฉันไม่สามารถนึกถึงประโยชน์ที่มีวัตถุ (3), ประโยชน์อย่างหนึ่งของการมี ID (2) & (1) คือเมื่อฉันสร้างวัตถุผู้ใช้จากฐานข้อมูลฉันไม่ต้องสร้างวัตถุหนังสือซึ่ง อาจจะขึ้นอยู่กับวัตถุผู้ใช้เองในการสร้างห่วงโซ่ที่ไม่มีที่สิ้นสุด มีวิธีแก้ไขปัญหาทั่วไปสำหรับทั้ง RDBMS และ No-SQL (ถ้าต่างกัน)?

จากคำตอบบางส่วนแล้วการ rephrasing คำถามของฉัน: (ด้วยการใช้ ID ที่ควรจะอยู่ในรูปแบบการห่อ) 1) ใช้ ID ทุกครั้งหรือไม่ 2) ใช้วัตถุเสมอ? 3) ใช้ ID เมื่อมีความเสี่ยงในการเรียกซ้ำในการซีเรียลไลซ์และดีซีเรียลไลซ์ แต่ใช้วัตถุเป็นอย่างอื่น? 4) มีอะไรอีกไหม?

แก้ไข: หากคุณตอบว่าควรใช้ออบเจกต์เสมอหรือในบางกรณีโปรดตรวจสอบให้แน่ใจว่าได้ตอบข้อกังวลที่ใหญ่ที่สุดที่ผู้ตอบคำถามคนอื่น ๆ โพสต์ไว้ => วิธีรับข้อมูลจาก DB


1
ขอขอบคุณสำหรับคำถามที่ดีรอคอยที่จะติดตามด้วยความสนใจ ความอัปยศเล็กน้อยที่ชื่อผู้ใช้ของคุณคือ "user18151" ผู้ที่ใช้ชื่อผู้ใช้ประเภทนี้จะถูกเพิกเฉย :)
bjfletcher

@bjfletcher ขอบคุณ ฉันมีการรับรู้ที่จู้จี้ตัวเอง แต่มันไม่เคยเกิดขึ้นกับฉันทำไม!
0fnt

คำตอบ:


7

Domain Objects เป็นรหัสสร้างปัญหาซับซ้อน / บอบบาง:

อันดับ / ซีเรียลไลซ์

หากคุณจัดเก็บวัตถุเป็นกุญแจสำคัญจะทำให้กราฟวัตถุเป็นอนุกรมที่ซับซ้อนมาก คุณจะได้รับstackoverflowข้อผิดพลาดเมื่อทำการทำให้ไร้เดียงสาเป็นอนุกรมกับ JSON หรือ XML เนื่องจากการเรียกซ้ำ จากนั้นคุณจะต้องเขียน serializer แบบกำหนดเองที่แปลงวัตถุจริงเพื่อใช้รหัสของพวกเขาแทนการทำให้เป็นอันดับวัตถุอินสแตนซ์และสร้างการสอบถามซ้ำ

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

การรั่วไหลของการอ้างอิงที่ลึกซึ้ง:

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

สถานการณ์ในอุดมคติ:

Id ทึบแสงเทียบกับ int / long:

idควรจะเป็นตัวระบุทึบแสงสมบูรณ์ที่ดำเนินการไม่มีข้อมูลเกี่ยวกับสิ่งที่จะระบุ แต่ควรเสนอการตรวจสอบว่าเป็นตัวระบุที่ถูกต้องในระบบของมัน

ประเภทดิบทำลายสิ่งนี้:

int, longและStringมีใช้กันมากที่สุดประเภทดิบสำหรับตัวบ่งชี้ในระบบ RDBMS มีประวัติอันยาวนานของเหตุผลเชิงปฏิบัติที่ย้อนกลับไปหลายสิบปีและพวกเขาล้วน แต่ถูกประนีประนอมซึ่งเหมาะกับการออมspaceหรือการออมtimeหรือทั้งสองอย่าง

รหัสลำดับเป็นผู้กระทำผิดที่เลวร้ายที่สุด:

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

String เขตข้อมูลเป็นปัญหาเนื่องจากนักออกแบบที่ไร้เดียงสาจะเก็บข้อมูลลงในเนื้อหาโดยปกติจะมีความหมายทางโลกเช่นกัน

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

จากนั้นแฮ็กก็เริ่มทำงานและสิ่งต่าง ๆ ทั้งหมดกลายเป็นกองนึ่ง

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

คุณจบลงด้วยปัญหาเดียวกันวิธีการทำให้ id ของคุณไม่ซ้ำกันทั่วโลก

UUID ถูกสร้างและสร้างมาตรฐานด้วยเหตุผล:

UUIDสามารถประสบปัญหาทั้งหมดที่กล่าวข้างต้นขึ้นอยู่กับที่Versionคุณใช้

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

Version 2ใช้ผู้ใช้UIDหรือGIDและโดมิโนUIDหรือGUIในสถานที่ที่เวลาจากVersion 1นี้เป็นสิ่งที่ไม่ดีเท่าVersion 1ที่การรั่วไหลของข้อมูลและความเสี่ยงข้อมูลที่จะใช้ในตรรกะทางธุรกิจ

Version 3คล้ายกัน แต่แทนที่ที่อยู่ MAC และเวลาด้วยMD5แฮชของอาเรย์บางอย่างbyte[]จากสิ่งที่มีความหมายอย่างแน่นอน ไม่มีการรั่วไหลของข้อมูลที่ต้องกังวลเกี่ยวกับคือไม่สามารถกู้คืนจากbyte[] UUIDนี่เป็นวิธีที่ดีในการสร้างUUIDฟอร์มอินสแตนซ์และคีย์ภายนอกของการจัดเรียงบางอย่าง

Version 4 ขึ้นอยู่กับตัวเลขสุ่มซึ่งเป็นทางออกที่ดีมันไม่มีข้อมูลความหมายอย่างแน่นอน แต่ไม่สามารถสร้างใหม่ได้อย่างแน่นอน

Version 5เป็นเหมือนVersion 4แต่ใช้แทนsha1md5

คีย์โดเมนและคีย์ข้อมูลธุรกรรม

การตั้งค่าของฉันสำหรับรหัสวัตถุโดเมนคือการใช้Version 5หรือVersion 3หากถูก จำกัด ไม่ให้ใช้Version 5ด้วยเหตุผลทางเทคนิคบางอย่าง

Version 3 เหมาะสำหรับข้อมูลธุรกรรมที่อาจแพร่กระจายไปในหลาย ๆ เครื่อง

ยกเว้นว่าคุณถูก จำกัด ด้วยพื้นที่ให้ใช้ UUID:

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

Version 3,4,5 ทึบแสงอย่างสมบูรณ์และนั่นคือวิธีที่พวกเขาควรจะเป็น

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

การจัดเก็บข้อมูลไม่ได้จะต้องมีCHAR(36)อย่างใดอย่างหนึ่ง คุณสามารถจัดเก็บUUIDในฟิลด์ไบต์ / บิต / หมายเลขดั้งเดิมสำหรับฐานข้อมูลที่กำหนดตราบเท่าที่ยังสามารถจัดทำดัชนีได้

มรดก

หากคุณมีประเภทดิบและไม่สามารถเปลี่ยนพวกเขาคุณยังสามารถแยกพวกเขาออกในรหัสของคุณ

การใช้Version 3/5ของUUIDคุณสามารถผ่านในClass.getName()+ String.valueOf(int)เป็น a byte[]และมีคีย์อ้างอิงทึบแสงที่สามารถกู้คืนได้และกำหนดได้


ฉันเสียใจมากถ้าฉันไม่ชัดเจนในคำถามของฉันและฉันรู้สึกแย่ (หรือดีจริง ๆ ) เพราะนี่เป็นคำตอบที่ยอดเยี่ยมและคิดได้ดีและคุณใช้เวลากับมันอย่างชัดเจน น่าเสียดายที่มันไม่ตรงกับคำถามของฉันบางทีมันอาจสมควรได้รับคำถามของตัวเอง "สิ่งที่ฉันควรทราบเมื่อสร้างฟิลด์รหัสสำหรับวัตถุโดเมนของฉัน"
0fnt

ฉันเพิ่มคำอธิบายที่ชัดเจน

รับทันที ขอบคุณที่ใช้เวลาตอบคำถาม
0fnt

1
Btw, AFAIK ผู้รวบรวมขยะทั่วไป (ซึ่งฉันเชื่อว่าเป็นระบบ GC ที่โดดเด่นในทุกวันนี้) ไม่ควรมีปัญหามากเกินไปในการอ้างอิงแบบวงกลมของ GC'ing
0fnt

1
ถ้าC-> A -> B -> AและBถูกใส่ลงไปCollectionแล้วAและทุกลูกจะยังคงสามารถเข้าถึงสิ่งเหล่านี้ไม่ได้ที่เห็นได้ชัดอย่างสมบูรณ์และสามารถนำไปสู่การที่ลึกซึ้งรั่วไหล GCเป็นปัญหาที่น้อยที่สุดการทำให้ซีเรียลไลซ์เซชั่นและดีซีเรียลไลเซชันของกราฟเป็นฝันร้ายของความซับซ้อน

2

ใช่มีประโยชน์ทั้งสองทางและยังมีการประนีประนอม

List<int>:

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

List<Book>:

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

หากคุณไม่มีหน่วยความจำหรือซีพียูที่เกี่ยวข้องกับฉันฉันจะList<Book>ใช้รหัสที่ใช้Userอินสแตนซ์นั้นจะสะอาดขึ้น

ประนีประนอม:

เมื่อใช้ Linq2SQL รหัสที่สร้างขึ้นสำหรับเอนทิตีผู้ใช้จะมีสิ่งEntitySet<Book>ที่ขี้เกียจโหลดเมื่อคุณเข้าถึง สิ่งนี้จะทำให้โค้ดของคุณสะอาดและอินสแตนซ์ของผู้ใช้มีขนาดเล็ก


สมมติว่าแคชบางประเภทประโยชน์การโหลดล่วงหน้าจะเป็นโมฆะ ฉันไม่ได้ใช้ Cassandra / HBase ดังนั้นจึงไม่สามารถพูดเกี่ยวกับพวกเขาได้ แต่ Linq2SQL เป็นกรณีที่เฉพาะเจาะจงมาก (แม้ว่าฉันจะไม่เห็นว่าการโหลดที่ขี้เกียจจะป้องกันกรณีการผูกมัดแบบไม่มีที่สิ้นสุดแม้ในกรณีเฉพาะนี้และในกรณีทั่วไป)
0fnt

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

คุณแน่ใจไหม? แม้ว่าฉันจะจัดเก็บหนังสือและผู้ใช้เป็นมาตรฐานแยกกันหรือไม่ สำหรับฉันดูเหมือนว่ามันควรจะเป็นค่าใช้จ่ายเพิ่มเติมแอบแฝงของเครือข่าย ไม่ว่าในกรณีใดคนเราจัดการกรณี RDBMS โดยทั่วไปได้อย่างไร? (ฉันได้แก้ไขคำถามที่จะพูดถึงอย่างชัดเจน)
0fnt

1

กฎง่ายๆสั้น ๆ :

ID ถูกใช้ในDTO s
การอ้างอิงวัตถุมักใช้ในวัตถุ Domain Logic / Business Logic และ UI layer

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


ขอบคุณที่หยุดและตอบ น่าเสียดายที่ในขณะที่ฉันเข้าใจความแตกต่างเนื่องจากลิงก์ wiki ฉันไม่เคยเห็นสิ่งนี้ในทางปฏิบัติ (เนื่องจากฉันไม่เคยทำงานกับโครงการระยะยาวขนาดใหญ่) คุณจะมีตัวอย่างที่แสดงวัตถุเดียวกันในสองวิธีเพื่อวัตถุประสงค์ที่แตกต่างกันสอง?
0fnt

นี่คือคำถามที่แท้จริงเกี่ยวกับการทำแผนที่: stackoverflow.com/questions/9770041/dto-to-entity-mapping-tool - และมีบทความที่สำคัญเช่นนี้: rogeralsing.com/2013/12/21
herzmeister

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

มองเข้าไปในรูปแบบพื้นที่เก็บข้อมูล คุณจะมีและBookRepository UserRepositoryคุณจะโทรmyRepository.GetById(...)หรือคล้ายกันเสมอและที่เก็บจะสร้างวัตถุและโหลดค่าจากแหล่งข้อมูลหรือรับจากแคช นอกจากนี้วัตถุเด็กส่วนใหญ่จะขี้เกียจโหลดซึ่งยังป้องกันไม่ให้มีการอ้างอิงวงกลมโดยตรงในเวลาก่อสร้าง
herzmeister
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.