Как использовать выражение для назначения свойства в LINQ. Выберите новый - PullRequest
0 голосов
/ 18 января 2019

У меня есть следующая ситуация в универсальном классе:

IQueryable<TQuote> query = GetQuotes(ctx)

, где ctx - это контекст базы данных, а GetQuotes возвращает DbSet<TQuote>.

Затем где-то вниз по кодузапрос выполнен.Его упрощенная форма выглядит следующим образом:

var list = await query
    .Select(v => new
    {
        v.Id,
        TimeZone = v.Property != null ? (int?)v.Property.TimeZone : null
        // and about 10 more simple properties like v.Id above
    }
    .ToListAsync();

, где Property - это свойство навигации (к другой таблице), а TimeZone - это просто обычный столбец / свойство базы данных типа int? в C #.

Все работало, пока я не попытался использовать этот универсальный класс с сущностью, у которой нет свойства навигации Property.Итак, я хотел бы заменить «жестко закодированное» выражение v.Property != null ? (int?)v.Property.TimeZone : null на абстрактный член класса, а затем переопределить его по-разному для различных типов TQuote.

Я пробовал что-то по этой сигнатуре:

protected abstract Expression<Func<TQuote, int?>> GetTimeZone();

, но потом, если я использую это в LINQ (сначала напрямую или присваивая какой-либо переменной), то сигнатура TimeZone также изменится наExpression<...> и если я пытаюсь ...Compile().Invoke(v), то LINQ жалуется, что LINQ для сущностей не поддерживает это.

Я видел этот ответ: Создайте динамическое выражение Linq to EF, чтобы выбрать IQueryable в новыйСвойства класса и присваивания Тем не менее, он создает весь селектор руками, и, учитывая, что у меня есть 16 свойств, создание и поддержание которых было бы затруднительно.Поэтому мне интересно, могу ли я что-то сделать только с этим TimeZone, но оставлю все остальное в простой форме LINQ, как указано выше.

Возможно ли это, и если да, то как именно?

1 Ответ

0 голосов
/ 18 января 2019

Попробуйте nuget LINQKit, https://github.com/scottksmith95/LINQKit.

Ниже моя попытка. LinqKit предоставляет методы AsExpandable() и Invoke(v). Я придумал свойства как Area.TimeZone и Region.RegionalTimeZone.

using LinqKit;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

class QuoteResult
{
    public int Id { get; set; }
    public int? TimeZone { get; set; }
    public string Note { get; set; }
}

abstract class QuoteHelper<TQuote> where TQuote : Quote
{
    protected abstract Expression<Func<TQuote, int?>> GetTimeZone { get; }

    public IEnumerable<QuoteResult> GetQuoteResults(
        EfExpressionPropertyDbContext ctx)
    {
        IQueryable<TQuote> query = GetQuotes(ctx);
        var getTimeZone = GetTimeZone;

        var list = query
            .AsExpandable()
            .Select(v => new QuoteResult
            {
                Id = v.Id,
                TimeZone = getTimeZone.Invoke(v),
                Note = v.Note
                // and about 10 more simple properties like v.Id above
            })
            .ToList();
        return list;
    }

    public IQueryable<TQuote> GetQuotes(
        EfExpressionPropertyDbContext ctx)
    {
        return ctx.Set<TQuote>();
    }
}

class CommonQuoteHelper : QuoteHelper<CommonQuote>
{
    protected override Expression<Func<CommonQuote, int?>> GetTimeZone
    {
        get { return q => q.Area != null ? (int?)q.Area.TimeZone : null; }
    }
}

class PeculiarQuoteHelper : QuoteHelper<PeculiarQuote>
{
    protected override Expression<Func<PeculiarQuote, int?>> GetTimeZone
    {
        get { return q => q.Region != null ? (int?)q.Region.RegionalTimeZone : null; }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...