Thay đổi chức năng thứ hai của bạn như thế này:
public IEnumerable<DO_RoleInfo> SelectAll()
{
Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>();
return from role in _ctx.DB_RoleInfo.ToList()
select Mapper.Map<DB_RoleInfo, DO_RoleInfo>(role);
}
AutoMapper chỉ hoạt động tốt với LINQ to SQL, nhưng nó không thể được thực hiện như một phần của truy vấn chậm. Thêm ToList()
vào cuối truy vấn LINQ của bạn làm cho nó ngay lập tức đánh giá kết quả, thay vì cố gắng dịch phân đoạn AutoMapper như một phần của truy vấn.
Làm rõ
Khái niệm chậm thực hiện (không "lười biếng tải") không có ý nghĩa gì một khi bạn đã thay đổi loại dẫn đến một cái gì đó không phải là một thực thể dữ liệu. Hãy xem xét hai loại cổ phiếu này:
public class DB_RoleInfo
{
public int ID { get; set; }
public string Name { get; set; }
}
public class DO_RoleInfo
{
public Role Role { get; set; } // Enumeration type
}
Bây giờ xem xét các bản đồ sau:
Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>
.ForMember(dest => dest.Role, opt => opt.MapFrom(src =>
(Role)Enum.Parse(typeof(Role), src.Name)));
lập bản đồ này là hoàn toàn tốt (trừ khi tôi thực hiện một typo), nhưng giả sử bạn viết phương pháp SelectAll
trong bài viết ban đầu của bạn thay vì sửa đổi của tôi:
public IQueryable<DO_RoleInfo> SelectAll()
{
Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>();
return from role in _ctx.DB_RoleInfo
select Mapper.Map<DB_RoleInfo, DO_RoleInfo>(role);
}
Đây thực sự là loại công việc, nhưng bằng cách tự gọi mình là "có thể truy vấn", nó nằm. Điều gì xảy ra nếu tôi cố gắng viết điều này chống lại nó:
public IEnumerable<DO_RoleInfo> SelectSome()
{
return from ri in SelectAll()
where (ri.Role == Role.Administrator) ||
(ri.Role == Role.Executive)
select ri;
}
Hãy suy nghĩ thật kỹ về điều này. Làm thế nào có thể LINQ to SQL có thể có thể biến thành công where
của bạn thành truy vấn cơ sở dữ liệu thực tế?
LINQ không biết gì về lớp học DO_RoleInfo
. Nó không biết cách lập bản đồ lạc hậu - trong một số trường hợp, thậm chí có thể không thực hiện được. Chắc chắn, bạn có thể xem mã này và truy cập "Ồ, thật dễ dàng, chỉ cần tìm kiếm 'Quản trị viên' hoặc 'Điều hành' trong cột Name
", nhưng bạn là người duy nhất biết điều đó. Theo như LINQ to SQL là có liên quan, truy vấn là vô nghĩa thuần túy.
Hãy tưởng tượng rằng ai đó đã cho bạn những hướng dẫn này:
Go to the supermarket and bring back the ingredients for making Morton Thompson Turkey.
Trừ khi bạn đã thực hiện nó trước, và hầu hết mọi người đã không, câu trả lời của bạn để hướng dẫn mà rất có thể sẽ là:
Bạn có thể đi chợ, và bạn có thể nhận được các thành phần cụ thể theo tên, nhưng bạn không thể đánh giá điều kiện tôi đã đưa cho bạn trong khi bạn đang ở đó. Tôi phải "bỏ bản đồ" các tiêu chí trước tiên. Tôi phải nói với bạn, đây là những thành phần chúng ta cần cho công thức này - bây giờ đi và lấy chúng.
Nói tóm lại, đây không phải là một số đơn giản sự không tương thích giữa LINQ to SQL và AutoMapper. Nó không phải là duy nhất cho một trong hai thư viện đó. Nó không quan trọng cách bạn thực sự thực hiện ánh xạ tới loại không phải thực thể - bạn có thể dễ dàng thực hiện ánh xạ theo cách thủ công và bạn vẫn nhận được cùng một lỗi, bởi vì bây giờ bạn đang đưa Linq cho SQL một bộ các hướng dẫn không còn dễ hiểu, xử lý các lớp bí ẩn không có bản đồ nội tại cho bất kỳ loại thực thể cụ thể nào.
Vấn đề này là cơ bản cho khái niệm về ánh xạ O/R và thực thi truy vấn bị trì hoãn. A chiếu là một hoạt động một chiều một chiều. Khi bạn dự án, bạn không còn có thể quay trở lại công cụ truy vấn và giả sử ồ tiện đây, sau đây là một số điều kiện khác cho bạn. Đã quá muộn. Điều tốt nhất bạn có thể làm là lấy những gì nó đã cung cấp cho bạn và tự mình đánh giá các điều kiện bổ sung.
Cuối cùng nhưng không kém phần quan trọng, tôi sẽ để bạn giải quyết. Nếu chỉ điều bạn muốn để có thể làm lại từ bản đồ của bạn là lọc các hàng, bạn có thể viết này:
public IEnumerable<DO_RoleInfo> SelectRoles(Func<DB_RoleInfo, bool> selector)
{
Mapper.CreateMap<DB_RoleInfo, DO_RoleInfo>();
return _ctx.DB_RoleInfo
.Where(selector)
.Select(dbr => Mapper.Map<DB_RoleInfo, DO_RoleInfo>(dbr));
}
Đây là một phương pháp hữu ích để xử lý các bản đồ cho bạn và chấp nhận một bộ lọc trên số thực đơn gốc và không phải là pháp nhân được ánh xạ. Nó có thể hữu ích nếu bạn có nhiều loại bộ lọc khác nhau nhưng luôn cần phải thực hiện cùng một ánh xạ.
Cá nhân, tôi nghĩ bạn sẽ tốt hơn chỉ cần viết ra các truy vấn đúng cách, trước tiên xác định những gì bạn cần truy xuất từ cơ sở dữ liệu, sau đó thực hiện bất kỳ phép chiếu/ánh xạ nào, và cuối cùng, nếu bạn cần làm thêm lọc (bạn không nên), rồi thực hiện kết quả với ToList()
hoặc ToArray()
và viết nhiều điều kiện hơn so với danh sách cục bộ.
Đừng cố gắng sử dụng AutoMapper hoặc bất kỳ công cụ nào khác để ẩn các đối tượng thực được hiển thị bởi LINQ to SQL.Mô hình miền là giao diện công khai của bạn. Các truy vấn bạn viết là một khía cạnh của việc thực hiện riêng riêng của bạn. Điều quan trọng là phải hiểu sự khác biệt và duy trì sự phân tách mối quan tâm tốt.
Chỉ cần một ghi chú trên bản cập nhật của bạn, thêm vào của tôi Trả lời: Phiên bản thứ hai hoạt động vì LINQ to SQL đã * biết * rằng bạn đã thực hiện một phép chiếu không thể đảo ngược; 'SelectByKey' thực sự chỉ sử dụng LINQ to Objects. Nếu bạn kiểm tra truy vấn thực tế đang được tạo ra, tôi nghĩ bạn sẽ thấy rằng nó vẫn đang chọn tất cả các thực thể từ cơ sở dữ liệu, tương đương với việc sử dụng 'ToList()' và sau đó lọc danh sách kết quả. – Aaronaught
Nó không phải là AutoMapper hỗ trợ LINQ. Đó là LINQ to SQL không hỗ trợ AutoMapper. Nhà cung cấp truy vấn LINQ to SQL nhìn vào cây biểu thức để xác định cách tạo truy vấn SQL. Khi nó đến phần Mapper.Map, nó không có ý tưởng làm thế nào để tạo ra các SQL. –