Làm thế nào để sử dụng mô hình kho lưu trữ một cách chính xác?


86

Tôi đang tự hỏi làm thế nào tôi nên nhóm các kho lưu trữ của mình? Giống như từ các ví dụ tôi đã thấy trên asp.net mvc và trong sách của tôi về cơ bản, chúng sử dụng một kho lưu trữ cho mỗi bảng cơ sở dữ liệu. Nhưng điều đó có vẻ như có rất nhiều kho lưu trữ dẫn đến việc bạn phải gọi đến nhiều kho lưu trữ sau này để chế nhạo và các thứ.

Vì vậy, tôi đoán tôi nên nhóm chúng. Tuy nhiên tôi không chắc làm thế nào để nhóm chúng.

Ngay bây giờ tôi đã tạo một Kho lưu trữ đăng ký để xử lý tất cả các nội dung đăng ký của mình. Tuy nhiên, có 4 bảng tôi cần cập nhật và trước đó tôi đã có 3 kho để thực hiện việc này.

Ví dụ một trong các bảng là bảng cấp phép. Khi họ đăng ký, tôi nhìn vào khóa của họ và kiểm tra xem có tồn tại trong cơ sở dữ liệu hay không. Bây giờ điều gì sẽ xảy ra nếu tôi cần kiểm tra khóa cấp phép này hoặc thứ gì đó khác từ bảng đó tại một số điểm khác sau đó đăng ký?

Một điểm có thể là đăng nhập (kiểm tra xem khóa chưa hết hạn).

Vậy tôi sẽ làm gì trong tình huống này? Viết lại mã một lần nữa (ngắt DRY)? Cố gắng gộp 2 kho này lại với nhau và hy vọng rằng không có phương pháp nào là cần thiết trong một số thời điểm khác (chẳng hạn như tôi có thể có một phương pháp kiểm tra xem userName có được sử dụng hay không - có lẽ tôi sẽ cần nó ở một nơi khác).

Ngoài ra nếu tôi hợp nhất chúng với nhau, tôi sẽ cần 2 lớp dịch vụ vào cùng một kho lưu trữ vì tôi nghĩ rằng việc có tất cả logic cho 2 phần khác nhau của một trang web sẽ dài và tôi sẽ phải có các tên như ValidateLogin (), ValdiateRegistrationForm () , ValdiateLoginRetrievePassword () và v.v.

Hay gọi là Kho lưu trữ và chỉ có một cái tên nghe kỳ lạ xung quanh?

Có vẻ khó để tạo một kho lưu trữ có tên đủ chung để bạn có thể sử dụng nó cho nhiều vị trí trong ứng dụng của mình mà vẫn có ý nghĩa và tôi không nghĩ rằng việc gọi một kho lưu trữ khác trong một kho lưu trữ sẽ là một phương pháp hay?


11
+1. Câu hỏi tuyệt vời.
đau buồn 30/09/09

Cảm ơn vì nó đã lỗi tôi một thời gian. Vì tôi thấy những điều tôi thấy trong sách quá đơn giản nên không chỉ cho bạn phải làm gì trong những tình huống này.
chobo2 30/09/09

Về cơ bản tôi đang làm giống như bạn và vâng nếu tôi có một lớp linq2sql được sử dụng trong nhiều hơn 1 kho lưu trữ và tôi cần thay đổi cấu trúc bảng mà tôi phá vỡ DRY. Ít hơn mức tiêu chuẩn. Bây giờ tôi lên kế hoạch tốt hơn một chút vì vậy tôi không cần phải sử dụng lớp linq2sql nhiều lần, điều mà tôi đoán là tốt để phân tách các mối quan tâm nhưng tôi thấy trước một ngày đây sẽ là một vấn đề thực sự đối với tôi.
đau buồn 30/09/09

Tôi đã hỏi một câu hỏi tương tự (nhưng không giống hệt nhau) ở đây: stackoverflow.com/questions/910156/…
Grokys 30/09/09

Ya nhưng có vẻ khó lên kế hoạch cho mọi tình huống. Giống như tôi đã nói, tôi có thể hợp nhất đăng nhập và đăng ký thành Xác thực và có 2 lớp riêng biệt. Điều đó có lẽ sẽ giải quyết vấn đề của tôi. Nhưng điều gì sẽ xảy ra nếu nói trang hồ sơ của trang web của tôi, tôi muốn cho họ xem khóa của họ vì bất kỳ lý do gì (có thể tôi sẽ để htem thay đổi nó hoặc điều gì đó). Bây giờ tôi phải làm gì để phá vỡ DRY và viết những điều tương tự? Hoặc cố gắng tạo một kho lưu trữ bằng cách nào đó có thể phù hợp với cả 3 bảng này với một cái tên hay.
chobo2 30/09/09

Câu trả lời:


41

Một điều mà tôi đã làm sai khi chơi với mô hình kho lưu trữ - giống như bạn, tôi nghĩ rằng bảng đó liên quan đến kho lưu trữ 1: 1. Khi chúng tôi áp dụng một số quy tắc từ Thiết kế theo hướng miền - vấn đề nhóm kho lưu trữ thường biến mất.

Kho lưu trữ phải là mỗi gốc Aggregate chứ không phải bảng. Nó có nghĩa là - nếu thực thể không nên sống một mình (tức là - nếu bạn có một thực Registrantthể tham gia cụ thể Registration) - thì nó chỉ là một thực thể, nó không cần kho lưu trữ, nó phải được cập nhật / tạo / truy xuất thông qua kho lưu trữ của gốc tổng hợp. thuộc về.

Tất nhiên - trong nhiều trường hợp, không thể áp dụng kỹ thuật giảm số lượng kho lưu trữ này (thực ra - nó là một kỹ thuật để cấu trúc mô hình miền của bạn) bởi vì mọi thực thể được cho là một gốc tổng hợp (điều đó phụ thuộc nhiều vào miền của bạn, Tôi chỉ có thể đưa ra những phỏng đoán mù quáng). Trong ví dụ của bạn - Licensedường như là một gốc tổng hợp vì bạn cần có thể kiểm tra chúng mà không có ngữ cảnh của Registrationthực thể.

Nhưng điều đó không hạn chế chúng ta đối với các kho lưu trữ theo tầng ( Registrationkho được phép tham chiếu Licensekho lưu trữ nếu cần). Điều đó không hạn chế chúng ta đến Licensekho lưu trữ tham chiếu (thích hợp - thông qua IoC) trực tiếp từ Registrationđối tượng.

Chỉ cần cố gắng không điều khiển thiết kế của bạn thông qua các phức tạp do công nghệ cung cấp hoặc hiểu sai điều gì đó. Nhóm các kho lưu trữ ServiceXchỉ vì bạn không muốn tạo 2 kho lưu trữ không phải là ý kiến ​​hay.

Tốt hơn hết là đặt cho nó một cái tên riêng - RegistrationServicetức là

Nhưng nói chung nên tránh các dịch vụ - chúng thường là nguyên nhân dẫn đến mô hình miền thiếu máu .

CHỈNH SỬA:
Bắt đầu sử dụng IoC. Nó thực sự làm dịu nỗi đau của việc phụ thuộc vào tiêm chích.
Thay vì viết:

var registrationService = new RegistrationService(new RegistrationRepository(),  
      new LicenseRepository(), new GodOnlyKnowsWhatElseThatServiceNeeds());

bạn sẽ có thể viết:

var registrationService = IoC.Resolve<IRegistrationService>();

Ps Sẽ tốt hơn nếu sử dụng cái gọi là bộ định vị dịch vụ thông thường nhưng đó chỉ là một ví dụ.


17
Hahaha ... Tôi đang đưa ra lời khuyên để sử dụng dịch vụ định vị. Luôn vui mừng khi thấy quá khứ mình đã ngu ngốc như thế nào.
Arnis Lapsa

1
@Arnis Có vẻ như ý kiến ​​của bạn đã thay đổi - Tôi quan tâm đến cách bạn trả lời câu hỏi này theo cách khác bây giờ?
ngm

10
@ngm đã thay đổi rất nhiều kể từ khi tôi trả lời câu hỏi này. Tôi vẫn đồng ý rằng gốc tổng hợp nên vẽ các ranh giới giao dịch (được lưu như một tổng thể), nhưng tôi ít lạc quan hơn nhiều về tính bền bỉ trừu tượng bằng cách sử dụng mẫu kho lưu trữ. Gần đây - tôi chỉ sử dụng ORM trực tiếp, vì những thứ như quản lý tải háo hức / lười biếng quá khó xử. Sẽ có lợi hơn nhiều nếu tập trung vào phát triển mô hình tên miền phong phú thay vì tập trung vào sự bền bỉ trừu tượng.
Arnis Lapsa

2
@Developer không, không chính xác. họ vẫn nên cố chấp không biết gì. bạn truy xuất gốc tổng hợp từ bên ngoài và gọi phương thức trên đó thực hiện công việc. mô hình miền của tôi không có tham chiếu nào, chỉ có những tham chiếu .net tiêu chuẩn. để đạt được điều đó, Bạn phải có mô hình tên miền phong phú và các công cụ đủ thông minh (NHibernate thực hiện thủ thuật).
Arnis Lapsa

1
Ngược lại. Tìm nạp nhiều hơn một tổng hợp thường có nghĩa là bạn có thể sử dụng PK hoặc chỉ mục. Nhanh hơn nhiều so với việc tận dụng các mối quan hệ mà EF tạo ra. Các tập hợp gốc càng nhỏ, thì hiệu suất trên chúng càng dễ dàng.
jgauffin

5

Một điều tôi đã bắt đầu làm để giải quyết vấn đề này là thực sự phát triển các dịch vụ bao bọc N kho. Hy vọng rằng khung DI hoặc IoC của bạn có thể giúp làm điều đó dễ dàng hơn.

public class ServiceImpl {
    public ServiceImpl(IRepo1 repo1, IRepo2 repo2...) { }
}

Điều đó có ý nghĩa? Ngoài ra, tôi hiểu rằng việc nói về các dịch vụ trong trang viên này có thể thực sự tuân thủ hoặc có thể không tuân thủ các nguyên tắc DDD, tôi chỉ làm điều đó vì nó có vẻ hiệu quả.


1
Nopethat không có nhiều ý nghĩa. Tôi không sử dụng khung DI hoặc IoC tại thời điểm hiện tại bởi vì tôi đã có đủ trên đĩa của mình.
chobo2 30/09/09

1
Nếu bạn có thể khởi tạo repo của mình w / just new (), bạn có thể thử this ... public ServiceImpl (): this (new Repo1, new Repo2 ...) {} như một hàm tạo bổ sung trong dịch vụ.
neouser99 30/09/09

Sự phụ thuộc tiêm chích? Tôi đã làm điều đó nhưng vẫn không chắc chắn mã của bạn là tiền đồng và những gì nó giải quyết.
chobo2 30/09/09

Tôi đặc biệt đi sau khi hợp nhất các kho lưu trữ. Mã nào không có ý nghĩa? Nếu bạn đang sử dụng DI, thì mã trong câu trả lời sẽ hoạt động theo nghĩa là khung DI của bạn sẽ đưa các dịch vụ IRepo đó vào, trong mã nhận xét về cơ bản, nó chỉ là một công việc nhỏ xung quanh để thực hiện DI (về cơ bản không hàm tạo tham số của bạn 'tiêm' những phụ thuộc đó vào ServiceImpl của bạn).
neouser99

Tôi đã sử dụng DI để tôi có thể kiểm tra đơn vị tốt hơn. Vấn đề của tôi là nếu bạn tạo các lớp dịch vụ và hệ thống đại diện với chi tiết tên. Sau đó, nếu bạn cần sử dụng chúng ở bất kỳ nơi nào khác, nó sẽ trông kỳ lạ khi gọi như Lớp Dịch vụ Đăng ký gọi RegRepo trong một số lớp khác như Lớp Hồ sơ. Vì vậy, tôi không thấy từ bạn ví dụ về những gì bạn hoàn toàn đang làm. Giống như Nếu bạn bắt đầu có quá nhiều Repos trong cùng một lớp dịch vụ, bạn sẽ có rất nhiều logic kinh doanh và logic xác nhận khác nhau. Vì trong lớp dịch vụ, bạn thường đặt logic xác thực. Tôi cần nhiều hơn nữa ...
chobo2

2

Những gì tôi đang làm là tôi có một lớp cơ sở trừu tượng được định nghĩa như sau:

public abstract class ReadOnlyRepository<T,V>
{
     V Find(T lookupKey);
}

public abstract class InsertRepository<T>
{
     void Add(T entityToSave);
}

public abstract class UpdateRepository<T,V>
{
     V Update(T entityToUpdate);
}

public abstract class DeleteRepository<T>
{
     void Delete(T entityToDelete);
}

Sau đó, bạn có thể dẫn xuất kho lưu trữ của mình từ lớp cơ sở trừu tượng và mở rộng kho lưu trữ duy nhất của bạn miễn là các đối số chung khác nhau chẳng hạn;

public class RegistrationRepository: ReadOnlyRepository<int, IRegistrationItem>,
                                     ReadOnlyRepository<string, IRegistrationItem> 

Vân vân....

Tôi cần các kho lưu trữ riêng biệt vì chúng tôi có những hạn chế đối với một số kho lưu trữ của mình và điều này mang lại cho chúng tôi sự linh hoạt tối đa. Hi vọng điêu nay co ich.


Vì vậy, bạn đang cố gắng tạo một kho lưu trữ chung để giải quyết tất cả những điều này?
chobo2 30/09/09

Vì vậy, những gì thực sự đi vào nói phương pháp Cập nhật. Giống như bạn đã thích bản cập nhật V này và nó chuyển vào một T entitytoUpdate nhưng không có mã nào thực sự cập nhật nó hay có?
chobo2 30/09/09

Có .. Sẽ có mã trong phương thức cập nhật bởi vì bạn sẽ viết một lớp giảm dần từ kho lưu trữ chung. Mã thực hiện có thể được Linq2SQL hoặc ADO.NET hoặc bất cứ điều gì mà bạn đã chọn như dữ liệu công nghệ thực hiện truy cập của bạn
Michael Mann

2

Tôi có đây là lớp kho lưu trữ của mình và vâng, tôi mở rộng trong kho lưu trữ bảng / khu vực nhưng đôi khi tôi vẫn phải phá vỡ DRY.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MvcRepository
{
    public class Repository<T> : IRepository<T> where T : class
    {
        protected System.Data.Linq.DataContext _dataContextFactory;

        public IQueryable<T> All()
        {
            return GetTable.AsQueryable();
        }

        public IQueryable<T> FindAll(Func<T, bool> exp)
        {
            return GetTable.Where<T>(exp).AsQueryable();
        }

        public T Single(Func<T, bool> exp)
        {
            return GetTable.Single(exp);
        }

        public virtual void MarkForDeletion(T entity)
        {
            _dataContextFactory.GetTable<T>().DeleteOnSubmit(entity);
        }

        public virtual T CreateInstance()
        {
            T entity = Activator.CreateInstance<T>();
            GetTable.InsertOnSubmit(entity);
            return entity;
        }

        public void SaveAll()
        {
            _dataContextFactory.SubmitChanges();
        }

        public Repository(System.Data.Linq.DataContext dataContextFactory)
        {
            _dataContextFactory = dataContextFactory;
        }

        public System.Data.Linq.Table<T> GetTable
        {
            get { return _dataContextFactory.GetTable<T>(); }
        }

    }
}

BIÊN TẬP

public class AdminRepository<T> : Repository<T> where T: class
{
    static AdminDataContext dc = new AdminDataContext(System.Configuration.ConfigurationManager.ConnectionStrings["MY_ConnectionString"].ConnectionString);

    public AdminRepository()
        : base( dc )
    {
    }

Tôi cũng có một tệp dữ liệu được tạo bằng cách sử dụng lớp Linq2SQL.dbml.

Vì vậy, bây giờ tôi có một kho lưu trữ tiêu chuẩn triển khai các lệnh gọi tiêu chuẩn như Tất cả và Tìm và trong Kho lưu trữ quản trị của tôi, tôi có các lệnh gọi cụ thể.

Không trả lời câu hỏi về KHÔ mặc dù tôi không nghĩ.


"Kho" để làm gì? và thích CreateInstance? Không chắc chắn những gì bạn có đang làm.
chobo2 30/09/09

Nó chung chung như bất cứ điều gì. Về cơ bản, bạn cần phải có một kho lưu trữ cụ thể cho (khu vực) của bạn. Kiểm tra bản chỉnh sửa ở trên cho AdminRepository của tôi.
đau buồn 30/09/09

1

Đây là một ví dụ về việc triển khai Kho lưu trữ chung bằng cách sử dụng FluentNHibernate. Nó có khả năng duy trì bất kỳ lớp nào mà bạn đã viết một trình liên kết. Nó thậm chí có khả năng tạo cơ sở dữ liệu của bạn dựa trên các lớp ánh xạ.


1

Mẫu kho lưu trữ là một mẫu thiết kế tồi. Tôi làm việc với nhiều dự án .Net cũ và mẫu này thường gây ra lỗi "Giao dịch phân tán", "Khôi phục một phần" và "Nhóm kết nối đã hết" có thể tránh được. Vấn đề là mẫu cố gắng xử lý các kết nối và giao dịch nội bộ nhưng chúng phải được xử lý ở lớp Bộ điều khiển. Ngoài ra EntityFramework đã tóm tắt rất nhiều logic. Tôi khuyên bạn nên sử dụng mẫu Dịch vụ để sử dụng lại mã được chia sẻ.


0

Tôi đề nghị bạn nhìn vào Kiến trúc Sắc nét . Họ đề xuất sử dụng một kho lưu trữ cho mỗi thực thể. Tôi hiện đang sử dụng nó trong dự án của mình và rất hài lòng với kết quả.


Tôi sẽ cho một +1 ở đây, nhưng anh ấy đã chỉ ra rằng các vùng chứa DI hoặc IoC không phải là một lựa chọn hoàn toàn (được cho rằng đó không phải là lợi ích duy nhất của Sharp Arch). Tôi đoán rằng có một số hoặc rất nhiều mã hiện có mà anh ấy đang làm việc.
neouser99 30/09/09

Những gì được coi là một thực thể? Đó có phải là toàn bộ cơ sở dữ liệu? hay đó là một bảng cơ sở dữ liệu? Các vùng chứa DI hoặc IoC không phải là một lựa chọn tại thời điểm này vì tôi không muốn học điều đó ngoài 10 thứ khác mà tôi đang học cùng một lúc. chúng là thứ mà tôi sẽ xem xét trong bản sửa đổi tiếp theo của trang web hoặc dự án tiếp theo của tôi. Mặc dù tôi không chắc nó sẽ là cái này nhưng nhìn nhanh vào trang web và có vẻ như tôi muốn bạn sử dụng nhirbrate và tôi đang sử dụng linq to sql tại thời điểm hiện tại.
chobo2
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.