Đối với bất cứ ai khác muốn dự án giá trị phi db từ một truy vấn db, this dự án từ u/Luis Aguilar là rất, rất hữu ích cho tôi.
Tôi đã có một cơ sở dữ liệu kế thừa rất lớn (450GB) được yêu cầu để được phân phát cho OData/WebAPI.
Yêu cầu OData có nghĩa là tôi không thể lọc dữ liệu nguồn (nhiều) trước khi trả lại cho người dùng. Chúng tôi có thể silo nó, nhưng ngoài ra nó là dữ liệu của họ để truy vấn như họ muốn.
Quan trọng hơn, dữ liệu cũ quá phức tạp để hiển thị nguyên trạng và có logic nghiệp vụ cần thiết để đối chiếu dữ liệu cần thiết (Include
thuộc tính điều hướng/khóa ngoại, vị từ mệnh đề dài, v.v.).
Điều này có nghĩa là phân trang và giới hạn kết quả sẽ không khả dụng cho đến sau khi truy vấn đã được thực hiện.
Phím tắt thông thường cho loại điều này liên quan đến các chiến lược khác nhau liên quan đến hiện thực hóa/tải dữ liệu. Tuy nhiên, do kích thước của tập dữ liệu và thiếu lọc, điều này sẽ dẫn đến sự bùng nổ bộ nhớ quá lớn và sự cố bộ nhớ ngoài.
Vì vậy, một số mã. Đây là cuộc gọi cấu hình của tôi, tương tự như những gì AutoMapper hoặc OData yêu cầu:
using ExpressionFramework.Projections;
using ExpressionFramework.Projections.Configuration;
public class ProjectionModelBuilder : ProjectionModel
{
protected override void OnModelCreating(ProjectionModelBuilder modelBuilder)
{
ClientDTO.ProjectionModel(modelBuilder);
OrderDTO.ProjectionModel(modelBuilder);
AnotherDTO.ProjectionModel(modelBuilder);
}
}
Thiết kế này cho phép tôi giữ nguyên quy tắc chiếu trong lớp DTO với phần còn lại của logic nghiệp vụ. Đây là những gì mã DTO cấp trông giống như:
public static void ProjectionModel(ProjectionModelBuilder modelBuilder)
{
modelBuilder
.Projection<ClientDTO>()
.ForSource<Client>(configuration =>
{
configuration.Property(dto => dto.Name).ExtractFrom(entity => entity.Name);
// etc
});
}
đâu Client
là Entity/EDM loại của tôi, ánh xạ tới db bảng và một gazillion phím nước ngoài.
Để sau đó nhận được một dịch/dự Queryable
, đây là nó:
IClientQueryService service = _ioc.Resolve<IClientQueryService>(); // Repository pattern
var q = service.GetClients(); // withManyNavigationIncludes
var r = q.Where<Item>(
i =>
i.Name != null
&& i.Name != ""
// lather rinse repeat, with many sub-objects navigated also
).AsQueryable();
var projectionModel = new ProjectionModelBuilder();
var s = projectionModel.Project<ClientDTO, Client>(r).AsQueryable();
Chỉ hai dòng cuối cùng có liên quan, nhưng bao gồm phần còn lại cho bối cảnh.
Điều cuối cùng tôi phải làm là đặt this.IsAutoConfigured = false;
trong hàm tạo cho ProjectionSourceTypeConfiguration.cs
trong mã của Luis; điều này cho phép tôi đặt hàng các định nghĩa chiếu của mình theo cách thủ công để các thuộc tính điều hướng bên trong các lớp cha sẽ định cấu hình các phép chiếu của chúng thành công.
Tôi không thể cảm ơn https://stackoverflow.com/users/543712/luis-aguilar đủ cho công việc của mình. Sau khi viết Nhà cung cấp LINQ của riêng tôi/ExpressionVisitor
với các lời gọi phương thức chung, bản dịch và bài hát khác để vẫn có nhiều vấn đề khác nhau, dự án của ông là một ơn trời.
Nếu bạn tìm đến phải đường ống xử lý biểu hiện của riêng bạn cho hiệu suất hoặc lý do khác, tôi khuyên bạn nên thesetwo câu trả lời để bắt đầu với.
Về cơ bản, bạn không thể làm điều đó * thuận tiện * - bạn phải sử dụng sự phản chiếu, và sau đó 'gõ' sẽ là' đối tượng' hoặc không chung chung 'IQueryable', và không có thứ gì khác sẽ công việc. Có những thứ bạn có thể làm ở đây, nhưng khá nhiều tất cả chúng sẽ xấu xí như bất cứ thứ gì ... không có viên đạn ma thuật ở đây. Là một lưu ý phụ, lệnh gọi 'Cast' sẽ là' ', không phải là' > '(nếu bạn sẽ tha thứ cho cú pháp giả khó xử đó) –
Chính xác thì bạn đang cố gắng làm gì: truy vấn vào một loại mà bạn chỉ biết khi chạy, hoặc mở rộng truy vấn để diễn tả một phép toán diễn xuất đối với một kiểu cụ thể mà bạn chỉ biết khi chạy? –
* Tại sao * bạn có muốn làm điều này không? Làm thế nào bạn nói bạn biết loại chỉ khi chạy, nhưng sau đó sử dụng nó như bạn biết nó tại thời gian biên dịch? – svick