ทำไม Active Record ทั้งหมดถึงเกลียดชัง? [ปิด]


103

ขณะที่ผมได้เรียนรู้มากขึ้นเกี่ยวกับ OOP และเริ่มต้นที่จะใช้รูปแบบการออกแบบต่างๆผมให้กลับมาที่กรณีที่มีผู้เกลียดActive Record

บ่อยครั้งที่ผู้คนพูดว่ามันปรับขนาดได้ไม่ดี (โดยอ้างว่า Twitter เป็นตัวอย่างหลักของพวกเขา) - แต่ก็ไม่มีใครอธิบายได้ว่าทำไมมันถึงปรับขนาดได้ไม่ดี และ / หรือวิธีบรรลุข้อดีของ AR โดยไม่มีข้อเสีย (ผ่านรูปแบบที่คล้ายกัน แต่แตกต่างกัน?)

หวังว่านี่จะไม่กลายเป็นสงครามศักดิ์สิทธิ์เกี่ยวกับรูปแบบการออกแบบ - ทั้งหมดที่ฉันอยากรู้คือ **** โดยเฉพาะ **** มีอะไรผิดปกติกับ Active Record

ถ้ามันปรับขนาดได้ไม่ดีทำไมล่ะ?

มันมีปัญหาอะไรอีก?


9
ฉันเดาว่าโดยทั่วไปแล้วความเกลียดและไม่ชอบต่อรูปแบบการออกแบบจำนวนมากเกี่ยวข้องกับการใช้งานที่ไม่ถูกต้อง ผู้คนมักใช้มากเกินไปและใช้ในบริบทที่ไม่ถูกต้องและลงเอยด้วยวิธีการแก้ปัญหาที่ซับซ้อนกว่าเดิม
terjetyl

1
การใช้ Active Record ของ Ruby เป็นเหมือน ORM
Jimmy T.

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

คำตอบ:


90

มีActiveRecord เป็นรูปแบบการออกแบบและActiveRecord the Rails ORM Libraryและยังมีโปรแกรม Knock-off สำหรับ. NET และภาษาอื่น ๆ อีกมากมาย

สิ่งเหล่านี้ล้วนเป็นสิ่งที่แตกต่างกัน ส่วนใหญ่เป็นไปตามรูปแบบการออกแบบนั้น แต่ขยายและปรับเปลี่ยนได้หลายวิธีดังนั้นก่อนที่ใครจะพูดว่า "ActiveRecord Sucks" จะต้องมีคุณสมบัติโดยพูดว่า "ActiveRecord ตัวไหนมีกอง?"

ฉันคุ้นเคยกับ ActiveRecord ของ Rails เท่านั้นฉันจะพยายามแก้ไขข้อร้องเรียนทั้งหมดที่เกิดขึ้นในบริบทของการใช้งาน

@BlaM

ปัญหาที่ฉันเห็นใน Active Records คือมันเป็นเพียงตารางประมาณหนึ่งเสมอ

รหัส:

class Person
    belongs_to :company
end
people = Person.find(:all, :include => :company )

สิ่งนี้จะสร้าง SQL ด้วยLEFT JOIN companies on companies.id = person.company_idและสร้างอ็อบเจ็กต์ของ บริษัท ที่เกี่ยวข้องโดยอัตโนมัติเพื่อให้คุณสามารถทำได้people.first.companyและไม่จำเป็นต้องกดฐานข้อมูลเนื่องจากมีข้อมูลอยู่แล้ว

@ pix0r

ปัญหาโดยธรรมชาติของ Active Record คือแบบสอบถามฐานข้อมูลจะถูกสร้างและดำเนินการโดยอัตโนมัติเพื่อเติมข้อมูลวัตถุและแก้ไขบันทึกฐานข้อมูล

รหัส:

person = Person.find_by_sql("giant complicated sql query")

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

@ ทิมซัลลิแวน

... และคุณเลือกหลายอินสแตนซ์ของโมเดลโดยพื้นฐานแล้วคุณกำลัง "เลือก * จาก ... "

รหัส:

people = Person.find(:all, :select=>'name, id')

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


ยิ่งใหญ่! ฉันไม่ทราบเกี่ยวกับคุณลักษณะเฉพาะนั้น ยังมีข้อโต้แย้ง pro-AR อีกสำหรับฉันที่จะใส่ลงในคลังแสงของฉัน
Tim Sullivan

การเข้าร่วมเป็นมากกว่ารูปแบบ Active Record
Jimmy T.

"Person.find_by_sql" ไม่ใช่รูปแบบ Active Record เลย "ระเบียนที่ใช้งาน" ค่อนข้างล้มเหลวฉันจึงต้องแก้ไขด้วยตนเอง
magallanes

52

ฉันพบเสมอว่า ActiveRecord นั้นดีสำหรับแอปพลิเคชันที่ใช้ CRUD อย่างรวดเร็วซึ่ง Model ค่อนข้างแบน (เช่นเดียวกับลำดับชั้นของคลาสไม่มากนัก) อย่างไรก็ตามสำหรับแอปพลิเคชันที่มีลำดับชั้น OO ที่ซับซ้อนDataMapperน่าจะเป็นทางออกที่ดีกว่า แม้ว่า ActiveRecord จะถือว่าอัตราส่วน 1: 1 ระหว่างตารางและออบเจ็กต์ข้อมูลของคุณ แต่ความสัมพันธ์ประเภทนั้นจะไม่สะดวกกับโดเมนที่ซับซ้อนมากขึ้น ในหนังสือของเขาเกี่ยวกับรูปแบบ Martin Fowler ชี้ให้เห็นว่า ActiveRecord มีแนวโน้มที่จะแยกย่อยภายใต้เงื่อนไขที่ Model ของคุณค่อนข้างซับซ้อนและแนะนำDataMapperเป็นทางเลือกอื่น

ฉันพบว่าสิ่งนี้เป็นจริงในทางปฏิบัติ ในกรณีที่คุณมีการสืบทอดจำนวนมากในโดเมนของคุณการแมปมรดกกับ RDBMS ของคุณทำได้ยากกว่าการแมปการเชื่อมโยงหรือองค์ประกอบ

วิธีที่ฉันทำคือการมีอ็อบเจ็กต์ "โดเมน" ที่คอนโทรลเลอร์ของคุณเข้าถึงผ่านคลาส DataMapper (หรือ "service layer") เหล่านี้ สิ่งเหล่านี้ไม่ได้สะท้อนฐานข้อมูลโดยตรง แต่ทำหน้าที่เป็นตัวแทน OO ของคุณสำหรับวัตถุบางอย่างในโลกแห่งความจริง สมมติว่าคุณมีคลาส User ในโดเมนของคุณและจำเป็นต้องมีการอ้างอิงถึงหรือคอลเล็กชันของอ็อบเจ็กต์อื่น ๆ ที่โหลดไว้แล้วเมื่อคุณเรียกดูอ็อบเจ็กต์ User นั้น ข้อมูลอาจมาจากตารางต่างๆมากมายและรูปแบบ ActiveRecord อาจทำให้ยากมาก

แทนที่จะโหลดอ็อบเจ็กต์ User โดยตรงและเข้าถึงข้อมูลโดยใช้ ActiveRecord style API โค้ดคอนโทรลเลอร์ของคุณจะดึงอ็อบเจ็กต์ User โดยการเรียก API ของเมธอด UserMapper.getUser () เป็นต้น เป็นผู้ทำแผนที่ที่รับผิดชอบในการโหลดอ็อบเจ็กต์ที่เกี่ยวข้องจากตารางที่เกี่ยวข้องและส่งคืนอ็อบเจ็กต์ "โดเมน" ของผู้ใช้ที่เสร็จสมบูรณ์ไปยังผู้เรียกใช้

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

อย่างไรก็ตามนั่นคือวิธีที่ฉันทำ


5
ดูเหมือนคุณจะไม่คุ้นเคยกับ ActiveRecord "ActiveRecord จะถือว่าอัตราส่วน 1: 1 ระหว่างตารางของคุณ" ไม่เป็นความจริงเลย ActiveRecord มีเวทมนตร์เชิงสัมพันธ์ที่ยอดเยี่ยมทุกประเภท ดูapi.rubyonrails.org/classes/ActiveRecord/Association/…
tybro0103

16
@ JoãoBragança - บางทีแทนที่จะเป็นการแสดงความคิดเห็นเชิงประชดประชันคุณสามารถอธิบายความยากลำบากที่เกิดขึ้นเมื่อข้อมูลของคน ๆ หนึ่งถูกทำให้เป็นเศษเล็กเศษน้อยดังนั้นพวกเราที่เหลือสามารถเรียนรู้บางสิ่งได้ :)
Taryn East

11

ฉันคิดว่ามีเหตุผลที่แตกต่างกันมากระหว่างสาเหตุที่ผู้คน "เกลียด" ActiveRecord กับสิ่งที่ "ผิด" กับมัน

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

หากต้องการเพิ่มธีมของการตอบกลับผู้แสดงความคิดเห็นที่พูดว่าสิ่งที่ยากใน ActiveRecord ด้วยการเข้าร่วมข้อมูลโค้ดอีกครั้ง

@Sam McAfee สมมติว่าคุณมีคลาส User ในโดเมนของคุณและจำเป็นต้องมีการอ้างอิงหรือคอลเลกชันของอ็อบเจ็กต์อื่น ๆ ที่โหลดไว้แล้วเมื่อคุณดึงอ็อบเจ็กต์ User นั้น ข้อมูลอาจมาจากตารางต่างๆมากมายและรูปแบบ ActiveRecord อาจทำให้ยากมาก

user = User.find(id, :include => ["posts", "comments"])
first_post = user.posts.first
first_comment = user.comments.first

ด้วยการใช้ตัวเลือกรวม ActiveRecord ช่วยให้คุณสามารถแทนที่พฤติกรรมการโหลดแบบขี้เกียจเริ่มต้นได้


8

คำตอบที่ยาวและช้าของฉันยังไม่สมบูรณ์ แต่เป็นคำอธิบายที่ดีว่าทำไมฉันถึงเกลียดรูปแบบนี้ความคิดเห็นและแม้แต่อารมณ์บางอย่าง:

1) เวอร์ชันสั้น: Active Record สร้าง " ชั้นบาง ๆ " ของ "การผูกที่แน่นหนา " ระหว่างฐานข้อมูลและรหัสแอปพลิเคชัน ซึ่งแก้ปัญหาได้อย่างไม่มีเหตุผลไม่มีปัญหาใด ๆ ไม่มีปัญหาเลย IMHO ไม่ได้ให้ค่าใด ๆ ยกเว้นน้ำตาลทางไวยากรณ์สำหรับโปรแกรมเมอร์ (ซึ่งอาจใช้ "ไวยากรณ์ของวัตถุ" เพื่อเข้าถึงข้อมูลบางส่วนซึ่งมีอยู่ในฐานข้อมูลเชิงสัมพันธ์) ความพยายามในการสร้างความสะดวกสบายให้กับโปรแกรมเมอร์ควร (IMHO ... ) ควรลงทุนในเครื่องมือการเข้าถึงฐานข้อมูลระดับต่ำเช่นวิธีการที่เรียบง่ายเรียบง่ายhash_map get_record( string id_value, string table_name, string id_column_name="id" )และคล้ายคลึงกัน (แน่นอนว่าแนวคิดและความสง่างามแตกต่างกันอย่างมากกับ ภาษาที่ใช้)

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

A1) ฐานข้อมูลเองตารางความสัมพันธ์แม้กระทั่งตรรกะบางอย่างหาก DBMS อนุญาต (MySQL ก็โตแล้วด้วย)

A2) บ่อยครั้งที่มีมากกว่าที่เก็บข้อมูล: ระบบไฟล์ (blobs ในฐานข้อมูลไม่ใช่การตัดสินใจที่ดีเสมอไป ... ), ระบบเดิม (ลองนึกภาพตัวเองว่า "จะเข้าถึง" ได้อย่างไรมีหลายประเภทที่เป็นไปได้ .. แต่นั่นคือ ไม่ใช่ประเด็น ... )

B) ชั้นการเข้าถึงฐานข้อมูล (ในระดับนี้วิธีการของเครื่องมือผู้ช่วยในการเข้าถึงข้อมูลในฐานข้อมูลนั้นเป็นที่น่ายินดีเป็นอย่างยิ่ง แต่ AR ไม่ได้ให้ค่าใด ๆ ที่นี่ยกเว้นน้ำตาลที่มีปฏิกิริยาบางอย่าง)

c) ชั้นวัตถุแอปพลิเคชัน: "วัตถุแอปพลิเคชัน" บางครั้งก็เป็นแถวธรรมดาของตารางในฐานข้อมูล แต่ส่วนใหญ่มักเป็นวัตถุผสมและมีตรรกะที่สูงกว่าดังนั้นการลงทุนเวลาในวัตถุ AR ในระดับนี้จึงไร้ประโยชน์โดยสิ้นเชิง เสียเวลาของผู้เขียนโค้ดอันมีค่าเนื่องจาก "มูลค่าที่แท้จริง" "ตรรกะที่สูงขึ้น" ของวัตถุเหล่านั้นจำเป็นต้องนำมาใช้กับวัตถุ AR อยู่แล้ว - มีและไม่มี AR! และตัวอย่างเช่นเหตุใดคุณจึงต้องการมีนามธรรมของ "วัตถุรายการบันทึก" รหัสลอจิกของแอปเขียนไว้ แต่ควรมีความสามารถในการอัปเดตหรือลบได้หรือไม่ ฟังดูงี่เง่าและApp::Log("I am a log message")ใช้งานง่ายกว่าขนาดle=new LogEntry(); le.time=now(); le.text="I am a log message"; le.Insert();. และตัวอย่างเช่น: การใช้ "วัตถุรายการบันทึก" ในมุมมองบันทึกในแอปพลิเคชันของคุณจะใช้ได้กับ 100, 1,000 หรือแม้แต่ 10,000 บรรทัดบันทึก แต่ไม่ช้าก็เร็วคุณจะต้องปรับให้เหมาะสม - และฉันเดิมพันในกรณีส่วนใหญ่คุณจะ ใช้คำสั่ง SQL SELECT ที่สวยงามขนาดเล็กในตรรกะของแอปของคุณ (ซึ่งทำลายแนวคิด AR โดยสิ้นเชิง .. ) แทนที่จะรวมคำสั่งเล็ก ๆ นั้นไว้ในกรอบความคิด AR แบบคงที่ที่มีการตัดโค้ดจำนวนมากและซ่อนไว้ เวลาที่คุณเสียไปกับการเขียนและ / หรือสร้างโค้ด AR อาจได้รับการลงทุนในอินเทอร์เฟซที่ชาญฉลาดมากขึ้นสำหรับการอ่านรายการบันทึก (หลายวิธีหลายวิธีท้องฟ้ามีขีด จำกัด ) Coders ควรกล้าที่จะคิดค้นนามธรรมใหม่ ๆเพื่อให้ตระหนักถึงตรรกะของแอปพลิเคชันที่เหมาะสมกับแอปพลิเคชันที่ต้องการและไม่นำรูปแบบโง่ ๆ มาใช้ซ้ำฟังดูดีตั้งแต่แรกเห็น!

ง) ตรรกะของแอปพลิเคชัน - ใช้ตรรกะของการโต้ตอบวัตถุและการสร้างการลบและการแสดงรายการ (!) ของวัตถุลอจิกของแอปพลิเคชัน (ไม่งานเหล่านั้นไม่ควรยึดติดกับวัตถุตรรกะของแอปพลิเคชันเอง: แผ่นกระดาษบนโต๊ะของคุณบอกหรือไม่ คุณชื่อและที่ตั้งของแผ่นงานอื่น ๆ ทั้งหมดในสำนักงานของคุณหรือไม่ลืมวิธีการ "คงที่" ในการแสดงรายการวัตถุนั่นเป็นเรื่องที่โง่เขลาการประนีประนอมที่ไม่ดีที่สร้างขึ้นเพื่อให้วิธีคิดของมนุษย์เข้ากันได้กับ -] การคิด AR)

จ) อินเทอร์เฟซผู้ใช้ - สิ่งที่ฉันจะเขียนในบรรทัดต่อไปนี้เป็นเรื่องที่เป็นส่วนตัวมาก แต่จากประสบการณ์ของฉันโครงการที่สร้างบน AR มักละเลยส่วน UI ของแอปพลิเคชัน - เสียเวลาไปกับการสร้างนามธรรมที่คลุมเครือ . ในท้ายที่สุดแอปพลิเคชันดังกล่าวเสียเวลากับผู้เขียนโค้ดเป็นจำนวนมากและรู้สึกเหมือนเป็นแอปพลิเคชันจาก coders สำหรับ coders ซึ่งมีความโน้มเอียงด้านเทคโนโลยีทั้งภายในและภายนอก คนเขียนโค้ดรู้สึกดี (ในที่สุดก็ทำงานหนักทุกอย่างเสร็จและถูกต้องตามคอนเซ็ปต์บนกระดาษ ... ) และลูกค้า "ต้องเรียนรู้ว่ามันต้องเป็นแบบนั้น" เพราะนั่นคือ "มืออาชีพ" .. โอเคขอโทษฉันพูดนอกเรื่อง ;-)

เป็นที่ยอมรับว่าทั้งหมดนี้เป็นเรื่องส่วนตัว แต่เป็นประสบการณ์ของฉัน (ยกเว้น Ruby on Rails อาจแตกต่างออกไปและฉันไม่มีประสบการณ์ในทางปฏิบัติกับแนวทางนั้น)

ในโครงการที่ต้องเสียเงินฉันมักได้ยินความต้องการที่จะเริ่มต้นด้วยการสร้างออบเจ็กต์ "บันทึกที่ใช้งานอยู่" บางอย่างเพื่อเป็นส่วนประกอบสำหรับตรรกะของแอปพลิเคชันระดับที่สูงขึ้น จากประสบการณ์ของฉันสิ่งนี้มักจะเห็นได้ชัดเป็นข้ออ้างบางประการสำหรับลูกค้า (บริษัท พัฒนาซอฟต์แวร์ในกรณีส่วนใหญ่) ไม่มีแนวคิดที่ดีมุมมองที่กว้างขวางภาพรวมของผลิตภัณฑ์ในที่สุด ลูกค้าเหล่านั้นคิดในกรอบที่เข้มงวด ("ในโครงการเมื่อสิบปีที่แล้วมันใช้งานได้ดี .. ") พวกเขาอาจแยกเอนทิตีออกพวกเขาอาจกำหนดความสัมพันธ์ของเอนทิตีพวกเขาอาจทำลายความสัมพันธ์ของข้อมูลและกำหนดตรรกะพื้นฐานของแอปพลิเคชัน แต่แล้วพวกเขาก็หยุด และส่งมอบให้คุณและคิดว่านั่นคือทั้งหมดที่คุณต้องการ ... พวกเขามักจะขาดแนวคิดที่สมบูรณ์เกี่ยวกับตรรกะของแอปพลิเคชันส่วนต่อประสานผู้ใช้ความสามารถในการใช้งานและอื่น ๆ ... พวกเขาขาดมุมมองที่กว้างขวางและพวกเขาขาดความรักต่อ รายละเอียดและพวกเขาต้องการให้คุณทำตามวิธี AR นั้นเพราะ .. ทำไมมันถึงได้ผลในโปรเจ็กต์นั้นเมื่อหลายปีก่อนมันทำให้ผู้คนไม่ว่างและเงียบ? ฉันไม่รู้ แต่ "รายละเอียด" แยกผู้ชายออกจากเด็กผู้ชายหรือ .. สโลแกนโฆษณาเดิมเป็นอย่างไร? ;-)

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

สุดท้าย: ทั้งหมดนี้คือสาเหตุที่ฉันเกลียด "รูปแบบการบันทึกที่ใช้งานอยู่" โง่ ๆ และฉันก็ทำและจะหลีกเลี่ยงทุกครั้งที่ทำได้

แก้ไข : ฉันจะเรียกสิ่งนี้ว่า No-Pattern ไม่สามารถแก้ปัญหาใด ๆ ได้ (รูปแบบไม่ได้มีไว้เพื่อสร้างน้ำตาลที่เป็นประโยค) มันสร้างปัญหามากมาย: ต้นตอของปัญหาทั้งหมด (กล่าวไว้ในคำตอบมากมายที่นี่ .. ) คือมันซ่อน SQL เก่าที่พัฒนามาอย่างดีและทรงพลังไว้เบื้องหลังอินเทอร์เฟซที่กำหนดรูปแบบได้ จำกัด มาก

รูปแบบนี้แทนที่ความยืดหยุ่นด้วยน้ำตาลซินแทติก!

ลองคิดดูว่า AR แก้ปัญหาอะไรให้คุณได้บ้าง?


1
เป็นรูปแบบสถาปัตยกรรมแหล่งข้อมูล บางทีคุณควรอ่าน Patterns of Enterprise Application Architecture ของ Fowler? ฉันมีความคิดคล้าย ๆ กับคุณก่อนที่จะใช้รูปแบบ / ORM จริง ๆ และพบว่ามันง่ายแค่ไหน
MattMcKnight

1
ฉันแบ่งปันความรู้สึกของคุณ ฉันได้กลิ่นบางอย่างผิดปกติเมื่อเฟรมเวิร์กไม่รองรับคีย์ผสม .... ฉันหลีกเลี่ยง ORM ประเภทใดก็ได้ก่อน SQLAlchemy และเรามักใช้มันในระดับที่ต่ำกว่าเป็นตัวสร้าง SQL ใช้ Data Mapper และมีความยืดหยุ่นมาก
Marco Mariani

1
ตั้งแต่สองวันที่ผ่านมาฉันมีส่วนร่วมในโครงการที่ใช้ ORM "ล้ำสมัย" บางทีการใช้งานอาจครบกำหนดแล้ว (เมื่อเทียบกับที่ฉันเคยทำเมื่อหลายปีก่อน) บางทีความคิดของฉันจะเปลี่ยนไปเราจะได้เห็นในอีกสามเดือน :-)
Frunsi

2
โครงการเสร็จแล้วรู้อะไรไหม? ORM ยังคงแย่อยู่ฉันเสียเวลาไปมากกับปัญหาการทำแผนที่ซึ่งแสดงในลักษณะเชิงสัมพันธ์กับ "รหัสเชิงวัตถุ" ได้อย่างง่ายดาย แน่นอนว่า ORM ให้วิธีในการแสดงแบบสอบถามในรูปแบบ OOP + SQL-Mix - แน่นอนในรูปแบบ OOP เหมือนกัน - แต่ใช้เวลามากกว่าเพียงแค่การเขียนแบบสอบถาม SQL สิ่งที่เป็นนามธรรมรั่วไหลออกมา "OOPSQLExperiment" ที่อยู่ด้านบนของ OOP - เพื่อให้ผู้ใช้เขียน SQL ในไวยากรณ์ OOP เป็นแนวคิดที่แย่ที่สุดเท่าที่เคยมีมา ไม่ไม่อีกเลย
Frunsi

1
ฉันเขียน SQL ดิบสำหรับทุกอย่างเป็นเวลาหลายปี Rails AR ทำให้ฉันหงุดหงิดในบางครั้งและสำหรับการสืบค้นแบบพาสซีฟฉันเกือบจะเห็นด้วยกับคุณ แต่นี่คือสิ่งที่แก้ได้: 1) ทำให้การบันทึกข้อมูลที่ไม่ผ่านการตรวจสอบความถูกต้องทำได้ยาก 2) ติดตามสิ่งที่เปลี่ยนแปลงในหน่วยความจำตั้งแต่ยังคงมีอยู่ 3) การใช้จุดที่ 2 เพื่อเขียนการbefore_saveเรียกกลับที่สมเหตุสมผลเพื่อรักษาความสอดคล้องภายในบันทึก 4) after_commitขอเกี่ยวสำหรับทริกเกอร์บริการภายนอก 5) DSL ที่ดีสำหรับจัดการการเปลี่ยนแปลง DDL เป็นชุดการเปลี่ยนแปลง (การโยกย้าย) (ยังคงมีความเจ็บปวดอยู่ แต่การไม่มีรูปแบบจะแย่ลงเมื่อผู้พัฒนา> 1 คน)
Adamantish

6

บางข้อความทำให้ฉันสับสน บางคำตอบจะเป็น "ORM" เทียบกับ "SQL" หรืออะไรทำนองนั้น

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

โดยปกติวัตถุเหล่านี้จะมีคุณลักษณะทางธุรกิจ (คุณสมบัติของถั่ว) และพฤติกรรมบางอย่าง (วิธีการที่มักจะทำงานกับคุณสมบัติเหล่านี้)

AR บอกเพียงว่า "เพิ่มวิธีการบางอย่างให้กับวัตถุโดเมนเหล่านี้" ให้กับงานที่เกี่ยวข้องกับฐานข้อมูล

และฉันต้องบอกว่าจากความคิดเห็นและประสบการณ์ของฉันฉันไม่ชอบรูปแบบ

ตั้งแต่แรกเห็นมันสามารถฟังดูดีทีเดียว เครื่องมือ Java สมัยใหม่บางอย่างเช่น Spring Roo ใช้รูปแบบนี้

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

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

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

อีกมุมมองหนึ่ง. ลองนึกภาพว่าเราไม่ได้ใช้ฐานข้อมูลเชิงสัมพันธ์ในการจัดเก็บวัตถุของเรา ลองนึกภาพว่าแอปพลิเคชันเก็บออบเจ็กต์โดเมนของเราไว้ในฐานข้อมูล NoSQL หรือในไฟล์ XML เป็นต้น เราจะใช้วิธีการทำงานเหล่านี้ในวัตถุโดเมนของเราหรือไม่? ฉันไม่คิดอย่างนั้น (ตัวอย่างเช่นในกรณีของ XM เราจะเพิ่มการอ้างอิงที่เกี่ยวข้องกับ XML ให้กับวัตถุโดเมนของเรา ... ฉันคิดว่าเศร้าจริงๆ) เหตุใดเราจึงต้องใช้เมธอด DB เชิงสัมพันธ์ในอ็อบเจ็กต์โดเมนดังที่รูปแบบ Ar กล่าว

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


ยินดีต้อนรับสู่ SO ชื่นชมความคิดเห็นของคุณ แต่คำถามนี้ถูกปิดโดยไม่สร้างสรรค์โดย NullUserException เมื่อวันที่ 17 ธ.ค. 54 เวลา 1:17
Tony Rad

3

คำถามเกี่ยวกับรูปแบบการออกแบบ Active Record ไม่ใช่เครื่องมือ orm

คำถามเดิมถูกแท็กด้วยรางและอ้างถึง Twitter ซึ่งสร้างขึ้นใน Ruby on Rails เฟรมเวิร์ก ActiveRecord ภายใน Rails เป็นการใช้รูปแบบการออกแบบ Active Record ของ Fowler


2

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

แน่นอนว่าการใช้งานที่แตกต่างกันจะจัดการสิ่งนี้แตกต่างกัน อย่างไรก็ตามมันเป็นปัญหาหนึ่ง

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

ฉันฉันขุด Active Record :-)

HTH


2
"การทำสิ่งนี้ด้วย Active Record จะทำให้คุณต้องเลือกคอลัมน์ทั้งหมด แต่ต้องใช้ City เท่านั้น" มันง่ายมากที่จะระบุคำสั่ง select
MattMcKnight

1

ฉันชอบวิธีที่ SubSonic ทำในคอลัมน์เดียว
ทั้ง

DataBaseTable.GetList(DataBaseTable.Columns.ColumnYouWant)

, หรือ:

Query q = DataBaseTable.CreateQuery()
               .WHERE(DataBaseTable.Columns.ColumnToFilterOn,value);
q.SelectList = DataBaseTable.Columns.ColumnYouWant;
q.Load();

แต่ Linq ยังคงเป็นราชาในเรื่องที่ขี้เกียจโหลด


1

@BlaM: บางครั้งฉันก็แค่ใช้บันทึกที่ใช้งานอยู่สำหรับผลลัพธ์ของการเข้าร่วม ไม่จำเป็นต้องเป็นตารางความสัมพันธ์ <--> Active Record เสมอไป ทำไมไม่ "ผลลัพธ์ของคำสั่ง Join" <--> Active Record?


1

ฉันจะพูดถึง Active Record เป็นรูปแบบการออกแบบฉันไม่เคยเห็น ROR

นักพัฒนาบางคนเกลียด Active Record เพราะพวกเขาอ่านหนังสือที่ชาญฉลาดเกี่ยวกับการเขียนโค้ดที่สะอาดและเรียบร้อยและหนังสือเหล่านี้ระบุว่า Active record ละเมิดหลักการตอบสนองเดียวละเมิดกฎ DDD ที่วัตถุในโดเมนควรเป็นสิ่งที่ไม่สนใจและกฎอื่น ๆ อีกมากมายจากหนังสือประเภทนี้ .

สิ่งที่สองวัตถุโดเมนใน Active Record มักจะเป็นแบบ 1 ต่อ 1 กับฐานข้อมูลซึ่งอาจถือได้ว่าเป็นข้อ จำกัด ในระบบบางประเภท (n-tier ส่วนใหญ่)

นั่นเป็นเพียงสิ่งที่เป็นนามธรรมฉันไม่เคยเห็นทับทิมบนรางการนำรูปแบบนี้ไปใช้จริง


0

ปัญหาที่ฉันเห็นใน Active Records คือมันเป็นเพียงตารางประมาณหนึ่งเสมอ ไม่เป็นไรตราบใดที่คุณทำงานกับตารางเพียงโต๊ะเดียว แต่เมื่อคุณทำงานกับข้อมูลส่วนใหญ่คุณจะมีส่วนร่วมอยู่ที่ไหนสักแห่ง

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


@BlaM: คุณพูดถูกจริงๆ แม้ว่าฉันจะไม่เคยใช้ Active Record แต่ฉันก็ใช้ระบบ ORM แบบสลักเกลียวอื่น ๆ (โดยเฉพาะ NHibernate) และมีข้อร้องเรียนใหญ่สองประการที่ฉันมี: วิธีโง่ ๆ ในการสร้างวัตถุ (เช่นไฟล์. hbm.xml ซึ่งแต่ละไฟล์ได้รับ รวบรวมไว้ในแอสเซมบลีของตัวเอง) และประสิทธิภาพการทำงานที่เกิดขึ้นเพียงแค่โหลดอ็อบเจ็กต์ (NHibernate สามารถขัดขวาง proc แบบ single-core เป็นเวลาหลายวินาทีในการเรียกใช้แบบสอบถามที่ไม่โหลดอะไรเลยเมื่อแบบสอบถาม SQL ที่เทียบเท่าแทบจะไม่มีการประมวลผล) ไม่เฉพาะเจาะจงสำหรับ Active Record แน่นอน แต่ฉันพบว่าระบบ ORM ส่วนใหญ่ (และระบบคล้าย ORM) ดูเหมือนจะเป็น
TheSmurf

มีทางเลือกมากมายในการใช้ไฟล์ hbm.xml ดูตัวอย่างเช่น NHibernate การทำแผนที่คุณสมบัติและ fluent-nhibernate
Mauricio Scheffer

เกี่ยวกับประสิทธิภาพการสร้างออบเจ็กต์ฉันไม่เคยประสบปัญหาความสมบูรณ์แบบนี้คุณอาจต้องการตรวจสอบกับผู้สร้างโปรไฟล์
Mauricio Scheffer

@mausch: ไม่จำเป็นต้องมีโปรไฟล์ เป็นปัญหาที่ค่อนข้างรู้จักกันดี ไม่ทราบว่าใช้กับเวอร์ชันล่าสุดหรือไม่ (ซึ่งฉันยังไม่ได้ใช้ในที่ทำงาน) ayende.com/Blog/archive/2007/10/26/…
TheSmurf

4
การใช้: join หรือ: include ใน IE Customer.find (: all,: include =>: contact,: condition => "active = 1") จะทำการรวม SQL ไม่ใช่การสแกนแบบเต็มตาราง
Tilendor

0

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

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


0

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


ActiveRecord แก้ปัญหาความต้านทานไม่ตรงกันได้จริงโดยให้คุณเขียนโค้ดในรูปแบบ OO เทียบกับสคีมาเชิงสัมพันธ์
Mauricio Scheffer

สนใจที่จะทำอย่างละเอียด? ฉันทามติทั่วไปคือวัตถุที่จำลองตามฐานข้อมูลเชิงสัมพันธ์ตามนิยามไม่ใช่เชิงวัตถุ (เนื่องจากฐานข้อมูลเชิงสัมพันธ์ไม่หมุนรอบแนวคิด OO เช่นการถ่ายทอดทางพันธุกรรมและความหลากหลาย)
Kevin Pang

มีสามวิธีที่ทราบกันดีในการแมปมรดกกับสคีมาเชิงสัมพันธ์ Ref: castleproject.org/ActiveRecord/documentation/trunk/usersguide/…
Mauricio Scheffer

ฉันคิดว่าคุณเข้าใจผิดโครงการ Castle Active Record OSS สำหรับ Active Record ในรูปแบบการออกแบบ คำถามเดิม (และคำตอบของฉัน) อ้างถึงรูปแบบการออกแบบ โครงการ Castle Active Record มีสิ่งต่างๆเข้ามาเพื่อช่วยในการพัฒนา OO แต่รูปแบบนั้นไม่มี
Kevin Pang

ฉันแค่อ้างปราสาทเป็นข้อมูลอ้างอิง ActiveRecord ของ RoR ใช้การสืบทอดตารางเดียวเท่านั้น ( martinfowler.com/eaaCatalog/singleTableInheritance.html ) แต่กำลังพิจารณากลยุทธ์อื่น ๆ ( blog.zerosum.org/2007/2/16/… )
Mauricio Scheffer

0

ลองสร้างความสัมพันธ์หลายรูปแบบหลาย ๆ แบบ ไม่ใช่เรื่องง่าย โดยเฉพาะอย่างยิ่งเมื่อคุณไม่ได้ใช้ STI

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