Как я могу проецировать объект таким образом, чтобы его можно было фильтровать в базе данных?C#

Место общения программистов C#
Ответить
Anonymous
 Как я могу проецировать объект таким образом, чтобы его можно было фильтровать в базе данных?

Сообщение Anonymous »

Я пытаюсь спроецировать результат следующего запроса на объекты EF Core 8:

Код: Выделить всё

select foo.*
, (case when hst.Id is not null and foo.OtherColumn = 1 then 42 else null end)
as Bar
from FooEntities foo
left join
FooEntities for system_time all hst on hst.Id          = foo.Id
and hst.OtherColumn = 999

Код: Выделить всё

FooEntity
s — это временная таблица, к которой я присоединяюсь самостоятельно, чтобы вычислить дополнительное возвращаемое значение. Я знаю, что самый простой способ добиться этого — использовать приведенный выше запрос в виде представления, но я намеренно избегаю этого, поскольку такая бизнес-логика должна определяться на C#, а не на SQL.
Я использую подход на основе модели (сущности, генерируемые из БД), поэтому начните с:

Код: Выделить всё

// generated from DB
public partial class FooEntity
{
public int Id { get; set; }

public byte OtherColumn { get; set; }

... other properties...
}

public partial class MyDbContext : DbContext
{
public virtual DbSet FooEntities { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity(... mapping configuration...);
}
}
Теперь я добавляю Bar из набора результатов как свойство, которое я не хочу, чтобы EF пытался заполнить или сохранить в базе данных:

Код: Выделить всё

// manually created
public partial class FooEntity
{
public int? Bar { get; set; }
}

public partial class MyDbContext
{
partial void OnModelCreatingPartial(ModelBuilder modelBuilder)
{
modelBuilder.Entity(entity => entity.Ignore(e => e.Bar));
}
}
Тогда у меня есть следующий метод LINQ-to-entities для инкапсуляции приведенного выше запроса:

Код: Выделить всё

public IQueryable QueryFoosWithBar(IQueryable foos)
{
return foos
.GroupJoin(
_dbContext.Set().TemporalAll()
.Where(hst => hst.OtherColumn == 999),
foo => foo.Id,
hst => hst.Id,
(foo, hst) => foo.MapBar(hst.DefaultIfEmpty().First() != default
&& foo.OtherColumn == 1 ? 42 : null));
}
где MapBar — это метод расширения, определенный как

Код: Выделить всё

public static FooEntity MapBar(
this FooEntity foo,
int? bar)
{
foo.Bar = bar;

return foo;
}
Если я материализую результат QueryFoosWithBar, я получу обратно объекты со свойством Bar, правильно заполненным в каждом случае. Однако мне нужно выполнить пост-фильтрацию результата QueryFoosWithBar в базе данных, до того, как он материализуется, и именно здесь EF взрывается с ужасным исключением:

Выражение LINQ... не может быть переведено

Другими словами, это работает:

Код: Выделить всё

... = await QueryFoosWithBar(... expression...).ToArrayAsync();
но это не так:

Код: Выделить всё

... = await QueryFoosWithBar(... expression...).OrderBy(f => f.Id).ToArrayAsync();
Я предполагаю, что это потому, что EF Core не понимает, что проецируемый FooEntity-with-

Код: Выделить всё

BarЭкземпляры 
по-прежнему являются объектом FooEntity, который он отслеживает; проверка сгенерированного SQL с помощью ToQueryString показывает, что вычисляемый столбец Bar не имеет псевдонима как такового, возможно, именно поэтому? Или я совершенно неправильно делаю то, что пытаюсь сделать?

Подробнее здесь: https://stackoverflow.com/questions/797 ... n-the-data
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»