2012-05-15 29 views
5

Tôi đã sử dụng Khuôn khổ thực thể với phương pháp tiếp cận POCO đầu tiên. Tôi đã theo dõi rất nhiều mô hình của Steve Sanderson trong cuốn sách 'Pro ASP.NET MVC 3 Framework' của mình, sử dụng một thùng chứa DI và lớp DbContext để kết nối với SQL Server.Cải thiện hiệu quả với Khung thực thể

Các bảng bên dưới trong máy chủ SQL chứa các bộ dữ liệu rất lớn được sử dụng bởi các ứng dụng khác nhau. Bởi vì điều này tôi đã phải tạo chế độ xem cho các thực thể tôi cần trong đơn đăng ký của mình:

class RemoteServerContext : DbContext 
{ 
    public DbSet<Customer> Customers { get; set; } 
    public DbSet<Order> Orders { get; set; } 
    public DbSet<Contact> Contacts { get; set; } 
    ... 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<Customer>().ToTable("vw_Customers"); 
     modelBuilder.Entity<Order>().ToTable("vw_Orders"); 
     ... 
    } 
} 

và điều này có vẻ phù hợp với hầu hết nhu cầu của tôi.

Vấn đề là tôi có một số những quan điểm có rất nhiều dữ liệu trong đó để khi tôi gọi cái gì đó như:

var customers = _repository.Customers().Where(c => c.Location == location).Where(...); 

nó dường như mang lại toàn bộ tập dữ liệu, mà có thể mất một thời gian trước khi truy vấn LINQ giảm tập hợp cho những người mà tôi cần. Điều này có vẻ rất không hiệu quả khi các tiêu chí chỉ áp dụng cho một vài bản ghi và tôi nhận được toàn bộ dữ liệu được đặt trở lại từ máy chủ SQL.

Tôi đã cố gắng để làm việc này bằng cách sử dụng thủ tục lưu trữ, chẳng hạn như

public IEnumerable<Customer> CustomersThatMatchACriteria(string criteria1, string criteria2, ...) //or an object passed in! 
{ 
    return Database.SqlQuery<Customer>("Exec pp_GetCustomersForCriteria @crit1 = {0}, @crit2 = {1}...", criteria1, criteria2,...); 
} 

trong khi đây là nhanh hơn nhiều, vấn đề ở đây là nó không trả lại một DbSet và vì vậy tôi mất tất cả các kết nối giữa các đối tượng của tôi, ví dụ Tôi không thể tham chiếu bất kỳ đối tượng liên quan nào như đơn đặt hàng hoặc liên hệ ngay cả khi tôi bao gồm ID của họ vì loại trả về là tập hợp 'Khách hàng' thay vì DbSet của chúng.

Có ai có cách nào tốt hơn để nhận máy chủ SQL để thực hiện truy vấn sao cho tôi không chuyển tải các dữ liệu không được sử dụng xung quanh?

Trả lời

4
var customers = _repository.Customers().Where(c => c.Location == location).Where(... 

Nếu Customers() lợi nhuận IQueryable, tuyên bố này một mình sẽ không thực sự được 'mang lại' bất cứ điều gì ở tất cả - gọi Where trên một IQueryable mang đến cho bạn IQueryable khác, và nó không phải cho đến khi bạn làm điều gì đó gây ra việc thực hiện truy vấn (chẳng hạn như ToList hoặc FirstOrDefault) rằng mọi thứ sẽ thực sự được thực hiện và kết quả được trả về.

Nếu phương thức Customers trả về một tập hợp các đối tượng đã được khởi tạo, thì có, vì bạn đang yêu cầu tất cả các đối tượng mà bạn nhận được tất cả.

Tôi chưa bao giờ sử dụng mã đầu tiên hoặc thậm chí là mẫu kho lưu trữ, vì vậy tôi không biết phải khuyên gì, ngoài việc ở trong lĩnh vực IQueryable càng lâu càng tốt và chỉ thực hiện truy vấn một lần bạn đã áp dụng tất cả các bộ lọc có liên quan.

+0

+1. Để biết thêm về 'cách tiếp cận mở rộng', bạn có thể viết một hàm lấy một vị từ và trả về '_repository.Customers() .Địa điểm (vị ngữ)' hoặc (nếu nó không phải là IQueryable nữa) hãy viết một hàm riêng biệt với 'context.CreateQuery ("Khách hàng") Ở đâu (vị ngữ) ', với khả năng gọi' .ToList() 'ở cuối. Nó sẽ xây dựng một biểu thức đẹp, được tối ưu hóa. –

+1

Xin chào. Bạn đã tìm được đề xuất của mình để ở lại trong lĩnh vực IQueryable. Tôi đã sử dụng một IEnumerable mà không vượt qua các truy vấn đến máy chủ nhưng được tất cả các hồ sơ và sau đó lọc chúng. Xem bài viết ở đây: http://www.fascinatedwithsoftware.com/blog/post/2011/06/27/IEnumerable-IQueryable-and-the-Entity-Framework-40.aspx Tôi đã kiểm tra với SQL Profiler và anh ấy đúng, IQueryable chuyển các tham số vào như một truy vấn – GrahamJRoy

0

Bạn cần truy vấn LINQ để trả về ít dữ liệu hơn như phân trang sql như top chức năng trong sql hoặc thực hiện truy vấn thủ công bằng cách sử dụng các thủ tục được lưu trữ. Trong cả hai trường hợp, bạn cần viết lại cơ chế truy vấn của mình. Đây là một trong những lý do tại sao tôi không sử dụng EF, bởi vì bạn không có nhiều quyền kiểm soát mã.

2

Những gì tôi đã có thể làm trở lại chỉ là một tập hợp các dữ liệu sẽ được như sau:

var customers = (from x in Repository.Customers where <boolean statement> &&/|| <boolean statement select new {variableName = x.Name , ...).Take(<integer amount for amount of records you need>); 

để ví dụ:

var customers = (from x in _repository.Customers where x.ID == id select new {variableName = x.Name}).take(1000); 

sau đó Lặp qua các kết quả để lấy dữ liệu: (hãy nhớ, câu lệnh linq trả lại một IQueryable) ...

foreach (var data in customers) 
{ 
    string doSomething = data.variableName; //to get data from your query. 
} 

hy vọng điều này sẽ giúp, không chính xác phương pháp tương tự, nhưng tôi thấy điều này tiện dụng trong mã của tôi

1

Có thể vì phương thức Cusomters() trong kho lưu trữ của bạn đang thực hiện một loại GetAll() và tìm nạp toàn bộ danh sách trước. Điều này nghiêm cấm LINQ và SQL Server của bạn tạo các truy vấn thông minh.

Tôi không biết nếu có một cách giải quyết tốt cho kho lưu trữ của bạn, nhưng nếu bạn muốn làm điều gì đó như:

using(var db = new RemoteServerContext()) 
{ 
    var custs = db.Customers.Where(...); 
} 

Tôi nghĩ rằng sẽ nhanh hơn rất nhiều. Nếu dự án của bạn đủ nhỏ, bạn có thể làm mà không có kho lưu trữ. Chắc chắn, bạn sẽ mất một lớp trừu tượng, nhưng với các dự án nhỏ này có thể không phải là một vấn đề lớn.

Mặt khác, bạn có thể tải tất cả Khách hàng trong kho của mình một lần và sử dụng bộ sưu tập kết quả trực tiếp (thay vì lệnh gọi phương thức điền vào danh sách). Cẩn thận với việc thêm, xóa và sửa đổi Khách hàng.

Các vấn đề liên quan