2016-08-15 3 views
0

Как достичь проекции на последний выбор? Мне нужно свойство, определяемое строкой prop.Name, которая будет выбрана в объект SeriesProjection.LINQ to SQL выбрать имя свойства по строке при проектировании

public override IQueryable<SeriesProjection> FilterOn(string column) 
{ 
    //Get metadata class property by defined Attributes and parameter column 
    var prop = typeof(CommunicationMetaData) 
       .GetProperties() 
       .Single(p => p.GetCustomAttribute<FilterableAttribute>().ReferenceProperty == column); 

    var attr = ((FilterableAttribute)prop.GetCustomAttribute(typeof(FilterableAttribute))); 

    var param = Expression.Parameter(typeof(Communication)); 

    Expression conversion = Expression.Convert(Expression.Property(param, attr.ReferenceProperty), typeof(int)); 

    var condition = Expression.Lambda<Func<Communication, int>>(conversion, param); // for LINQ to SQl/Entities skip Compile() call 

    var result = DbQuery.Include(prop.Name) 
      //.GroupBy(c => c.GetType().GetProperty(attr.ReferenceProperty)) 
      .GroupBy(condition) 
      .OrderByDescending(g => g.Count()) 
      .Select(group => new SeriesProjection() 
      { 
       Count = group.Count(), 
       Id = group.Key, 
       //set this navigation property dynamically 
       Name = group.FirstOrDefault().GetType().GetProperty(prop.Name) 
      }); 

    return result; 
} 

Для GroupBy я использовал имя Fk свойства, которое всегда ИНТ на Communication лица, но и для выбора я не могу понять выражение.

[EDIT]

System.Data.Entity.Infrastructure.DbQuery<Communication> DbQuery; 
--- 
[MetadataType(typeof(CommunicationMetaData))] 
public partial class Communication 
{ 
    public int CommunicationId { get; set; } 
    public Nullable<int> TopicId { get; set; } 
    public int CreateById { get; set; } 
    public virtual Employee CreateByEmployee { get; set; } 
    public virtual Topic Topic { get; set; } 
} 
--- 
public class CommunicationMetaData 
{ 
    [Filterable("By Employee", nameof(Communication.CreateById))] 
    public Employee CreateByEmployee { get; set; } 
    [Filterable("By Topic", nameof(Communication.TopicId))] 
    public Topic Topic { get; set; } 
} 
--- 
[AttributeUsage(AttributeTargets.Property)] 
public class FilterableAttribute : System.Attribute 
{ 

    public FilterableAttribute(string friendlyName, string referenceProperty) 
    { 
     FriendlyName = friendlyName; 
     ReferenceProperty = referenceProperty; 
    } 

    public string FriendlyName { get; set; } 

    public string ReferenceProperty { get; set; } 
} 
--- 
public class SeriesProjection 
{ 
    public int Count { get; set; } 
    public int Id { get; set; } 
    public object Name { get; set; } 
} 
+0

Для более опытных глаз это, вероятно, не понадобится, но могли бы вы также опубликовать классы 'SeriesProjection',' CommunicationMetaData', 'FilterableAttribute',' Communication' и 'DbQuery' вместе с вводом' column', чтобы я мог протестировать? – uTeisT

+0

Вы создали выражение GroupBy, зачем останавливаться на нем? –

+0

@JeffMercado, это точно моя борьба, поскольку я не могу понять это. –

ответ

1

Без некоторого выражения хелперов библиотеки, вы должны создать выражение селектора все вручную.

На вход селектора будет параметр типа IGrouping<int, Communication>, тип результата - SeriesProjection, а тело будет MemberInit выражение:

var projectionParameter = Expression.Parameter(typeof(IGrouping<int, Communication>), "group"); 
var projectionType = typeof(SeriesProjection); 
var projectionBody = Expression.MemberInit(
    // new SeriesProjection 
    Expression.New(projectionType), 
    // { 
    //  Count = group.Count(), 
    Expression.Bind(
     projectionType.GetProperty(nameof(SeriesProjection.Count)), 
     Expression.Call(typeof(Enumerable), "Count", new[] { typeof(Communication) }, projectionParameter)), 
    //  Id = group.Key 
    Expression.Bind(
     projectionType.GetProperty(nameof(SeriesProjection.Id)), 
     Expression.Property(projectionParameter, "Key")), 
    //  Name = group.FirstOrDefault().Property 
    Expression.Bind(
     projectionType.GetProperty(nameof(SeriesProjection.Name)), 
     Expression.Property(
      Expression.Call(typeof(Enumerable), "FirstOrDefault", new[] { typeof(Communication) }, projectionParameter), 
      prop.Name)) 
    // } 
    ); 
var projectionSelector = Expression.Lambda<Func<IGrouping<int, Communication>, SeriesProjection>>(projectionBody, projectionParameter); 

, а затем, конечно, использовать просто:

var result = DbQuery.Include(prop.Name) 
     .GroupBy(condition) 
     .OrderByDescending(g => g.Count()) 
     .Select(projectionSelector);