Как передать выражение > для создания дерева выражений с другими значениями для использования в Entity Framework - PullRequest
0 голосов
/ 25 мая 2020

Это немного сложно объяснить, поэтому проще всего использовать пример.

Я пытался выполнить Fun c в Fun c, но он не поддерживается Linq to Entities.

Итак, сначала, что работает ...

internal class CategoryHolder<T>
{
    public int FamilyId { get; set; }
    public T CategoryData { get; set; }
}

public class StatusFilterData
{
    public string Status { get; set; }
    public bool HasOutcomes { get; set; }
}

public List<FollowUpsCategoryStatistics<StatusFilterData>> GetFollowUpIdsGroupedByFamily(int teamMemberId)
{

    Expression<Func<FollowUp, CategoryHolder<StatusFilterData>>> groupingKey = fup => 
        new CategoryHolder<StatusFilterData>()
        {
            FamilyId = fup.Family.Id,
            CategoryData = new StatusFilterData
            {
                Status = fup.Status.ToString(),
                HasOutcomes = fup.Campaign.FollowUpsOutcomes
                    .Any(outcome => outcome.ContactedMemberId == fup.Campaign.FollowUpsTeam.Id)
            }
        };

    //GetAssignedOpenFollowUps returns IQueryable<FollowUp> which from EF: DbSet<FollowUp>
    var doubleGroups = GetAssignedOpenFollowUps(teamMemberId)
        .GroupBy(groupingKey)
        .GroupBy(g => g.Key.CategoryData)
        .ToList();


    [...code removed for brevity]
}

Это довольно просто. Чтобы получить правильные группировки и связанные с ними числа и т. Д. c., Мне нужно дважды сгруппировать данные, сначала используя FamilyId и CategoryData, а второй раз просто CategoryData. Первая группировка всегда будет использовать FamnilyId, но тип CategoryData generi c, который используется как в 1-й, так и во 2-й группировках, может измениться (в приведенном выше примере это объект StatusFilterData). Вышеупомянутое работает хорошо, и оно правильно дает результат, который мне нужен, но только для сценария, где CategoryData имеет тип StatusFilterData.

То, что я пытаюсь сделать, но не получается, - это создать CategoryHolder. CategoryData Dynami c путем преобразования функции в generi c и передачи Expression, чтобы я мог определить результат в вызывающем коде, таким образом:

private List<FollowUpsCategoryStatistics<FollowUpsServices.StatusFilterData>> GetStatusFilterData()
{
    var currentUser = new SessionHelper().GetCurrentUser();
    var result = _followUpsServices.GetFollowUpIdsGroupedByFamily(
        currentUser,
        fup => new FollowUpsServices.StatusFilterData
        {
            Status = fup.Status.ToString(),
            HasOutcomes = fup.Campaign.FollowUpsOutcomes
                .Any(outcome => outcome.ContactedMemberId == fup.Campaign.FollowUpsTeam.Id)
        }
    );

    return result;
}

public List<FollowUpsCategoryStatistics<TReturn>> GetFollowUpIdsGroupedByFamily<TReturn>(
    int teamMemberId,
    Expression<Func<FollowUp, TReturn>> categoryDataFunc
)
{

    Expression<Func<FollowUp, CategoryHolder<TReturn>>> groupingKey = fup => 
        new CategoryHolder<TReturn>()
        {
            FamilyId = fup.Family.Id,
            CategoryData = categoryDataFunc.Compile().Invoke(fup)
        };

    //GetAssignedOpenFollowUps returns IQueryable<FollowUp> which from EF: DbSet<FollowUp>
    var doubleGroups = GetAssignedOpenFollowUps(teamMemberId)
        .GroupBy(groupingKey)
        .GroupBy(g => g.Key.CategoryData)
        .ToList();

    [...code removed for brevity]
}

Хотя компилятор с этим согласен , Linq to Entities не так, как Fun c в Fun c не поддерживается - проблема в categoryDataFunc.Compile().Invoke(fup) с существующим выражением.

Я пытался найти, как создать дерево выражений, но, честно говоря, я борюсь и потратил часы на то, чтобы никуда не спешить, поскольку деревья выражений для меня в новинку, и, хотя есть несколько отличных примеров, я не могу понять, как применить какие-либо из них к мой конкретный c сценарий.

Если у кого-то есть знания и время, чтобы помочь, я был бы благодарен за помощь.

Ура,

Павел

...