มันเป็นวิธีปฏิบัติที่ไม่ถูกต้องที่ตัวควบคุมเรียกที่เก็บแทนการบริการ


43

มันเป็นวิธีปฏิบัติที่ไม่ถูกต้องที่ตัวควบคุมเรียกที่เก็บแทนการบริการ

เพื่ออธิบายเพิ่มเติม:

ฉันคิดว่าในการควบคุมการออกแบบที่ดีโทรบริการและพื้นที่เก็บข้อมูลการใช้บริการ

แต่บางครั้งในคอนโทรลเลอร์ฉันไม่มี / ต้องการตรรกะใด ๆ และเพียงแค่ต้องดึงข้อมูลจาก db และส่งต่อให้ดู

และฉันสามารถทำได้โดยเพียงแค่เรียกที่เก็บ - ไม่จำเป็นต้องโทรหาบริการ - มันเป็นการปฏิบัติที่ไม่ดี?


คุณเรียกบริการอย่างไร ผ่านส่วนต่อประสาน REST?
Robert Harvey

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

3
Meh หากเป็นแอปพลิเคชั่นขนาดเล็กและคุณเพียงแค่พยายามรับข้อมูลจากฐานข้อมูลเลเยอร์บริการจะเสียเวลาเว้นแต่ว่าเลเยอร์บริการนั้นเป็นส่วนหนึ่งของ API สาธารณะเช่นอินเทอร์เฟซ REST "นมดีสำหรับคุณหรือไม่ดีสำหรับคุณ" ขึ้นอยู่กับว่าคุณแพ้แลคโตสหรือไม่
Robert Harvey

4
ไม่มีกฎที่ยากและรวดเร็วที่คุณควรมี Controller -> Service -> โครงสร้างที่เก็บข้อมูลเหนือ Controller -> Repository เลือกรูปแบบที่เหมาะสมสำหรับแอปพลิเคชันที่เหมาะสม สิ่งที่ฉันจะพูดคือคุณควรทำให้ใบสมัครของคุณสอดคล้องกัน
NikolaiDante

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

คำตอบ:


31

ไม่คิดอย่างนี้: พื้นที่เก็บข้อมูลเป็นบริการ (ด้วย)

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

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

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


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

ฉันสังเกตเห็นรหัสที่ค่อนข้างซับซ้อนเพื่อปรับการใช้บริการ ไร้สาระอย่างน้อย ...
Gi1ber7

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

การเข้าถึง DAO โดยตรงเป็นสิ่งที่อันตรายในตัวควบคุมมันสามารถทำให้คุณไวต่อการฉีด SQL และให้การเข้าถึงการกระทำที่อันตรายเช่น ,, ลบทั้งหมด '' ฉันจะหลีกเลี่ยงอย่างแน่นอน
Anirudh

4

ไม่ใช่วิธีปฏิบัติที่ไม่ดีสำหรับคอนโทรลเลอร์ที่จะเรียกที่เก็บโดยตรง "บริการ" เป็นเพียงเครื่องมืออื่นดังนั้นใช้งานในที่ที่เหมาะสม

NikolaiDante แสดงความคิดเห็น:

... เลือกรูปแบบที่เหมาะสมสำหรับแอพพลิเคชั่นที่เหมาะสม สิ่งที่ฉันจะพูดคือคุณควรทำให้ใบสมัครของคุณสอดคล้องกัน

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

เพื่อส่งเสริมความกังวลและการทดสอบที่แยกจากกันได้ดีพื้นที่เก็บข้อมูลควรขึ้นกับที่คุณฉีดเข้าไปในบริการผ่าน Constructor:

IFooRepository repository = new FooRepository();
FooService service = new FooService(repository);

service.DoSomething(...);

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

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

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

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

public class ShoppingCartsController : Controller
{
    [HttpPost]
    public ActionResult Edit(int id, ShoppingCartForm model)
    {
        // Controller initiates a database session and transaction
        using (IStoreContext store = new StoreContext())
        {
            // Controller goes directly to a repository to find a record by Id
            ShoppingCart cart = store.ShoppingCarts.Find(id);

            // Controller creates the service, and passes the repository and/or
            // the current transaction
            ShoppingCartService service = new ShoppingCartService(store.ShoppingCarts);

            if (cart == null)
                return HttpNotFound();

            if (ModelState.IsValid)
            {
                // Controller delegates to a service object to manipulate the
                // Domain Model (ShoppingCart)
                service.UpdateShoppingCart(model, cart);

                // Controller decides to commit changes
                store.SaveChanges();

                return RedirectToAction("Index", "Home");
            }
            else
            {
                return View(model);
            }
        }
    }
}

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

การแบ่งความรับผิดชอบเป็นดังนี้:

  • คอนโทรลเลอร์ควบคุมการไหลของแอปพลิเคชัน
    • ส่งคืน "404 Not Found" หากตะกร้าสินค้าไม่ได้อยู่ในฐานข้อมูล
    • แสดงฟอร์มอีกครั้งด้วยข้อความตรวจสอบความถูกต้องหากการตรวจสอบล้มเหลว
    • บันทึกรถเข็นหากทุกอย่างเช็คเอาท์
  • คอนโทรลเลอร์ได้รับมอบให้กับคลาสบริการเพื่อดำเนินการตรรกะทางธุรกิจในรูปแบบโดเมนของคุณ (หรือเอนทิตี) วัตถุบริการไม่ควรใช้ตรรกะทางธุรกิจ! พวกเขาใช้ตรรกะทางธุรกิจ
  • ตัวควบคุมอาจมอบหมายโดยตรงไปยังที่เก็บสำหรับการดำเนินการอย่างง่าย
  • วัตถุบริการใช้ข้อมูลในรูปแบบมุมมองและมอบให้แก่ Domain Models เพื่อดำเนินการตรรกะทางธุรกิจ (เช่นวิธีการเรียกใช้วัตถุบริการในรุ่นโดเมนก่อนที่จะเรียกวิธีการในพื้นที่เก็บข้อมูล)
  • บริการวัตถุมอบหมายให้กับที่เก็บข้อมูลการคงอยู่ของข้อมูล
  • ผู้ควบคุมควร:
    1. จัดการอายุการใช้งานของธุรกรรมหรือ
    2. สร้างหน่วยการทำงานของวัตถุเพื่อจัดการอายุการใช้งานของธุรกรรม

1
-1 สำหรับการวาง DbContext ลงในคอนโทรลเลอร์แทนที่จะเป็น repo repo นั้นมีวัตถุประสงค์เพื่อจัดการผู้ให้บริการข้อมูลดังนั้นไม่มีใครที่จะต้องทำในกรณีที่มีการเปลี่ยนแปลงผู้ให้บริการข้อมูล (จาก MySQL เป็นไฟล์ JSON แบบคงที่, เปลี่ยนแปลงในที่เดียว)
Jimmy Hoffa

@JimmyHoffa: จริงๆแล้วฉันมองย้อนกลับไปที่รหัสที่ฉันเขียนและตามจริงฉันสร้างวัตถุ "บริบท" สำหรับที่เก็บของฉันไม่จำเป็นต้องใช้ฐานข้อมูล ฉันคิดว่าDbContextเป็นชื่อที่ไม่ดีในกรณีนี้ ฉันจะเปลี่ยนสิ่งนั้น ฉันใช้ NHibernate และที่เก็บ (หรือบริบทถ้าเป็นประโยชน์) จัดการจุดสิ้นสุดของฐานข้อมูลดังนั้นการเปลี่ยนกลไกการคงอยู่ไม่จำเป็นต้องมีการเปลี่ยนแปลงโค้ดนอกบริบท
เกร็ก Burghardt

ดูเหมือนว่าคุณจะสับสนกับตัวควบคุมด้วยที่เก็บของรหัสของคุณ ... ฉันหมายถึง "บริบท" ของคุณผิดทั้งหมดและไม่ควรมีอยู่จริงในคอนโทรลเลอร์
Jimmy Hoffa

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

1
พื้นที่เก็บข้อมูลโดยทั่วไปแล้วจะรับผิดชอบข้อมูลบริบทของข้อมูลทั้งหมดเพื่อให้แน่ใจว่าไม่มีสิ่งใดที่จำเป็นต้องรู้เกี่ยวกับข้อมูลนอกเหนือจากสิ่งที่โดเมนจำเป็นต้องรู้
Jimmy Hoffa

1

ขึ้นอยู่กับสถาปัตยกรรมของคุณ ฉันใช้สปริงและบริการได้รับการจัดการโดยเสมอ

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

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

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