2010-03-18 40 views
7

Tôi sử dụng LINQ-SQL làm DAL của mình, sau đó tôi có một dự án có tên là DB hoạt động như BLL của tôi. Các ứng dụng khác nhau sau đó truy cập BLL để đọc/ghi dữ liệu từ Cơ sở dữ liệu SQL.Sự khác nhau giữa các truy vấn LINQ này là gì?

tôi có những phương pháp trong BLL của tôi cho một bảng cụ thể:

public IEnumerable<SystemSalesTaxList> Get_SystemSalesTaxList() 
{ 
     return from s in db.SystemSalesTaxLists 
       select s; 
} 

public SystemSalesTaxList Get_SystemSalesTaxList(string strSalesTaxID) 
{ 
    return Get_SystemSalesTaxList().Where(s => s.SalesTaxID == strSalesTaxID).FirstOrDefault(); 
} 

public SystemSalesTaxList Get_SystemSalesTaxListByZipCode(string strZipCode) 
{ 
    return Get_SystemSalesTaxList().Where(s => s.ZipCode == strZipCode).FirstOrDefault(); 
} 

Tất cả khá thẳng về phía trước, tôi nghĩ.

Get_SystemSalesTaxListByZipCode luôn trả về giá trị null, ngay cả khi nó có Mã ZIP tồn tại trong bảng đó.

Nếu tôi viết những phương pháp như thế này, nó sẽ trả hàng Tôi muốn:

public SystemSalesTaxList Get_SystemSalesTaxListByZipCode(string strZipCode) 
{ 
    var salesTax = from s in db.SystemSalesTaxLists 
        where s.ZipCode == strZipCode 
        select s; 

    return salesTax.FirstOrDefault(); 
} 

Tại sao các phương pháp khác không trở về như nhau, như truy vấn nên giống hệt nhau?

Lưu ý rằng, quá tải Get_SystemSalesTaxList(string strSalesTaxID) trả về một bản ghi tốt khi tôi cung cấp cho nó SalesTaxID hợp lệ.

Có cách nào hiệu quả hơn để viết các loại lớp "trợ giúp" này không?

Cảm ơn!

+0

ngốc câu hỏi - bạn có chắc là bạn đang chuyển mã ZipCode sang 'Get_SystemSalesTaxListByZipCode'? – Oded

+1

Vấn đề là, như đã xác định, 'IEnumerable '- nhưng tôi chỉ khóc để nói" nó có lẽ là cách phàn nàn về ký hiệu hungarian ";-p –

Trả lời

7

Đây có thể là các cách khác nhau LINQ xử lý IEnumerable<T>IQueryable<T>.

Bạn đã khai báo Get_SystemSalesTaxList khi trả lại IEnumerable<SystemSalesTaxList>. Điều đó có nghĩa là khi trong mẫu mã đầu tiên của bạn, bạn áp dụng toán tử Where cho kết quả của Get_SystemSalesTaxList, nó được giải quyết theo phương thức mở rộng Enumerable.Where. (Lưu ý rằng điều quan trọng là loại tuyên bố Vâng, tại Get_SystemSalesTaxList runtime được trả lại một IQueryable<SystemSalesTaxList>, nhưng nó tuyên bố loại -. Những gì trình biên dịch thấy - là IEnumerable<SystemSalesTaxList>.) Enumerable.Where chạy .NET ngữ quy định trong mục tiêu trình tự. Trong trường hợp này, nó lặp lại trên tất cả các đối tượng SystemSalesTaxList được trả về bởi Get_SystemSalesTaxList, sinh ra những thuộc tính ZipCode bằng chuỗi mã zip được chỉ định (sử dụng toán tử .NET String ==).

Nhưng trong mẫu mã cuối cùng của bạn, bạn áp dụng toán tử Where to db.SystemSalesTaxList, được khai báo là loại IQueryable<SystemSalesTaxList>. Vì vậy, toán tử Where trong mẫu đó được giải quyết thành Queryable.Where, dịch biểu thức biến vị ngữ đã chỉ định thành SQL và chạy nó trên cơ sở dữ liệu. Vì vậy, những gì khác nhau trong các phương pháp mã zip là cái đầu tiên chạy thử nghiệm C# s.ZipCode == strZipCode trong .NET và thứ hai dịch thành truy vấn SQL WHERE ZipCode = 'CA 12345' (tham số SQL thực sự nhưng bạn có được ý tưởng). Tại sao những điều này cho kết quả khác nhau? Khó chắc chắn, nhưng thuộc tính C# == phân biệt chữ hoa chữ thường và tùy thuộc vào cài đặt đối chiếu của bạn, SQL có thể có hoặc không phân biệt chữ hoa chữ thường. Vì vậy, sự nghi ngờ của tôi là strZipCode không phù hợp với mã zip cơ sở dữ liệu trong trường hợp, nhưng trong phiên bản thứ hai SQL Server collation là làm mịn này hơn.

Giải pháp tốt nhất có thể là thay đổi tuyên bố Get_SystemSalesTaxList để trả về IQueryable<SystemSalesTaxList>. Lợi ích chính của điều này là nó có nghĩa là các truy vấn được xây dựng trên Get_SystemSalesTaxList sẽ được thực hiện bên cơ sở dữ liệu.Hiện tại, các phương thức của bạn đang lấy lại EVERYTHING trong bảng cơ sở dữ liệu và lọc nó ở phía máy khách. Thay đổi việc khai báo sẽ nhận được các truy vấn của bạn được dịch sang SQL và chúng sẽ chạy hiệu quả hơn nhiều, và hy vọng sẽ giải quyết vấn đề mã zip của bạn thành món hời.

+0

Làm cho tinh thần với tôi, và chính xác là loại câu trả lời tôi đã tìm kiếm để nhận được khi đăng câu hỏi! Cảm ơn bạn. – SnAzBaZ

1

Vấn đề thực sự ở đây là sử dụng IEnumerable<T>, làm hỏng "thành phần" của truy vấn; này có hai tác dụng:

  • bạn đang đọc bài (hoặc ít nhất, nhiều hơn bạn cần) của bảng của bạn mỗi lần, ngay cả khi bạn yêu cầu một hàng duy nhất
  • bạn đang chạy LINQ-to-Objects quy tắc, vì vậy trường hợp nhạy cảm áp dụng

Thay vào đó, bạn muốn được sử dụng IQueryable<T> bên trong lớp dữ liệu của bạn, cho phép bạn kết hợp nhiều truy vấn với thêm Where, OrderBy, Skip, Take, vv khi cần thiết và có nó xây dựng TSQL để phù hợp (và sử dụng các quy tắc về độ nhạy của trường hợp db của bạn).

Có cách nào hiệu quả hơn để viết các loại lớp "trợ giúp" này không?

Đối với hiệu quả hơn (ít mã để gỡ lỗi, không dòng toàn bộ bảng, sử dụng tốt hơn của bản sắc-bản đồ để ngắn mạch tra cứu bổ sung (qua FirstOrDefault vv)):

public IEnumerable<SystemSalesTaxList> Get_SystemSalesTaxList() 
{ 
    return db.SystemSalesTaxLists; 
} 

public SystemSalesTaxList Get_SystemSalesTaxList(string salesTaxID) 
{ 
    return db.SystemSalesTaxLists.FirstOrDefault(s => s.SalesTaxID==salesTaxID); 
} 

public SystemSalesTaxList Get_SystemSalesTaxListByZipCode(string zipCode) 
{ 
    return db.SystemSalesTaxLists.FirstOrDefault(s => s.ZipCode == zipCode); 
} 
+0

Mặc dù xem thêm lưu ý của tôi ở đây (http://stackoverflow.com/questions/2469816/what-is-the-best-way-to-determine-if-table-already-has-record-with-specific-id/ 2469836 # 2469836) cho sự khác biệt giữa 'Where (predicate) .irstOrDefault()' và 'FirstOrDefault (predicate)' giữa .NET 3.5/3.5SP1/4.0 –

+0

Cảm ơn, không chỉ một mà là hai câu trả lời tuyệt vời cho câu hỏi của tôi! – SnAzBaZ

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