Подтвердить что ты не робот

Кастинг на производный тип в запросе LINQ to Entities с наследованием Table Per Hierarchy

У меня есть модель LINQ для сущностей с наследованием Table Per Hierarchy. У меня есть запрос по базовому типу, и я хочу выполнить определенную зависящую от типа логику. Например:

IQueryable<BaseType> base = ...

// this works fine
var result = base.Select(b => b is DerivedType1 ? 1 : 2).ToList();

// this doesn't compile to SQL
var result2 = base.Select(b => b is DerivedType1 ? ((DerivedType1)b).DerivedProperty : null).ToList();

Есть ли способ сделать что-то подобное без обработки IQueryables каждого производного типа отдельно:

// I'd rather not do this:
var resultA = base.OfType<DerivedType1>().Select(d => d.DerivedProperty);
var resultB = base.OfType<DerivedType2>().Select(d => default(int?));
var result = resultA.Concat(resultB).ToList();
4b9b3361

Ответ 1

Прямое литье к типу объекта типа (DerivedType1)b не поддерживается с LINQ-to-Entities, но оператор as (b as DerivedType1), следовательно, вы можете попробовать:

var result2 = base
    .Select(b => b is DerivedType1
        ? (b as DerivedType1).DerivedProperty
        : null)
    .ToList();

Ответ 2

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

public class MyBaseClass
{
    public virtual int GetSomething()
    {
        throw new NotImplementedException();
    }
}

public class MyDerivedClass1 : MyBaseClass
{
    public int SomeProperty { get; set; }

    public override int GetSomething()
    {
        return this.SomeProperty;
    }
}

public class MyDerivedClass2 : MyBaseClass
{
    public int SomeOtherProperty { get; set; }

    public override int GetSomething()
    {
        return this.SomeOtherProperty;
    }
}

Тогда вы могли бы:

var result = base.Select(b => b.GetSomething()).ToList();

Ответ 3

Попробуйте это, я никогда не делал ничего, что нужно было делать, но это должно сделать это. Кроме того, если вы используете base, прежде всего, не потому, что это ключевое слово, но если вы должны использовать @base, то перед именем это означает, что он не используется как ключевое слово.

var resultA = base.Select(aVar =>
                            (aVar is DerivedType1) ?
                                (DerivedType)(((DerivedType1)aVar).DerivedProperty)
                                :
                                (DerivedType)(default(int?))
                        ).ToList();

Ответ 4

OfType<DerivedType1>() 

вернет IEnumerable, если возможно, попытайтесь перейти на базовый тип на IEnumerable вместо IQueryable, вы можете ограничить некоторые ограничения SQL при использовании IQueryable.

Это, конечно, если вы фактически не запрашиваете базу данных?

Ответ 5

Вы можете использовать EntityFramework.Extended, чтобы повысить производительность запроса, вместо того, чтобы делать 2 раунда поездки в DB.

var resultA = base.OfType<DerivedType1>().Select(d => d.DerivedProperty).Future();
var resultB = base.OfType<DerivedType2>().Select(d => default(int?)).Future();
var result = resultA.Concat(resultB).ToList();

В этом случае выполняется только одна обратная поездка в bd. Эта структура очень полезна для многих других вещей int EF