2012-01-11 43 views
7

Chúng tôi đang cố gắng truyền một phiên bản IQueryable<EntityObject> tới một số IQueryable<SpecificEntityObject>, loại SpecificEntityObject chỉ được biết khi chạy.Truyền IQueryable <EntityObject> đến IQueryable <Specific>

Chúng tôi đã thử sử dụng mã bên dưới, không biên dịch vì Loại hoặc không gian tên 'objType' không tồn tại.

var t = query.ElementType; 
Type objType = typeof(IQueryable<>).MakeGenericType(t); 
var typed = query.Cast<IEnumerable<objType>>(); 


var grouped = typed.GroupByMany(groupBy.Select(grp => grp.Expression).ToArray()); 

Bất kỳ ý tưởng nào?

+2

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ử đó) –

+2

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? –

+0

* 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

Trả lời

5

Sử dụng sau IQueryable mở rộng phương pháp chung query.ToDTO<sourceType,DestType>();:

public static class QueryableExtensions 
{ 
    public static IQueryable<TDest> ToDTO<TSource, TDest>(this IQueryable<TSource> source) 
    { 
     List<TDest> destinationList = new List<TDest>(); 
     List<TSource> sourceList = source.ToList<TSource>(); 

     var sourceType = typeof(TSource); 
     var destType = typeof(TDest); 
     foreach (TSource sourceElement in sourceList) 
     { 
      TDest destElement = Activator.CreateInstance<TDest>(); 
      //Get all properties from the object 
      PropertyInfo[] sourceProperties = typeof(TSource).GetProperties(); 
      foreach (PropertyInfo sourceProperty in sourceProperties) 
      { 
       //and assign value to each propery according to property name. 
       PropertyInfo destProperty = destType.GetProperty(sourceProperty.Name); 
       destProperty.SetValue(destElement, sourceProperty.GetValue(sourceElement, null), null); 
       destinationList.Add(destElement); 
      } 
     } 

     return destinationList.AsQueryable(); 
    } 
} 
+0

Mã đẹp và tôi sử dụng nó trong dự án của mình. Một thông báo nhỏ: destinationList.Add (destElement); nên được ra khỏi dấu ngoặc đơn. –

0

Nếu bạn bắt đầu sử dụng phản chiếu, bạn cũng cần sử dụng nó với tất cả các phương pháp. Vì vậy, bạn cần phải tạo

var myEnumType = typeof(IEnumerable<>).MakeGenericType(objType); 

và cũng tìm phương pháp mở rộng Loại kết hợp cần có khi chạy.

myEnumType.GetMethod("Cast", BindingFlags.Public | 
       BindingFlags.Static, 
       null, 
       CallingConventions.Any, 
       new Type[] {typeof(object)}, 
       null); 

sau đó bạn sẽ có thể gọi là phương pháp

0
var t = query.ElementType; 
Type objType = typeof(IQueryable<>).MakeGenericType(t); 
var typed = query.Cast<object>(); 


var grouped = typed.GroupByMany(groupBy.Select(grp => grp.Expression).ToArray()); 
+0

Xin chào, chào mừng bạn đến với SO. Bạn có thể đưa ra một số lời giải thích cho giải pháp của bạn? – GraphicsMuncher

1

Đố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.

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