Я пытаюсь написать следующий запрос с аналогичной моделью. Я думаю, что понимаю проблему, но не смог отредактировать модель таким образом, чтобы не добавлять новые столбцы внешнего ключа в базовую таблицу.
Было бы также знать, почему, когда я добавляю базы в родительский элемент, он добавляет новые столбцы для Base, D1 и D2 в таблицу Base. Кажется, это наименее ожидаемый результат.
public List Bases { get; set; }
Ошибка:
Необработанное исключение. System.InvalidOperationException: выражение LINQ 'DbSet()
.Join(inner: DbSet(),
outerKeySelector: b => EF.Property(b, "BaseId"),
innerKeySelector: b0 => EF.Property(b0, "ID"),
resultSelector: (o, i) => new TransparentIdentifier(
Outer = o,
Inner = i
))
.Where(b => b.Inner.Parent.ID == 1)' не удалось перевести.
Дополнительная информация: не удалось перевести элемент «Parent» для типа сущности «Base». Обычно это происходит, когда указанный элемент не сопоставлен. Либо перепишите запрос в форме, которую можно перевести, либо явно переключитесь на оценку клиента, вставив вызов AsEnumerable, AsAsyncEnumerable, ToList или ToListAsync. Дополнительную информацию см. на https://go.microsoft.com/fwlink/?linkid=2101038.
в Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.Translate(выражение выражения)
в Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutorExpression[TResult](Expression запрос)
в Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](запрос выражения)
в Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](запрос выражения, логическое асинхронное значение)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](база данных IDatabase, запрос-выражение, модель IModel, логическая асинхронность)
в Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.c__DisplayClass11_01.b__0() at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func1 компилятор)
в Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteCore[TResult](запрос выражения, Boolean async, CancellationToken cancelToken)
в Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](запрос выражения, CancellationToken cancelToken)
в Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](выражение-выражение, CancellationToken cancelToken)
в Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable1.GetAsyncEnumerator(CancellationToken cancellationToken) at System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable1.GetAsyncEnumerator()
в Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](источник IQueryable`1, CancellationToken cancelToken)
в Program.$(String[] args) в C:\Users\Anthony\RiderProjects\efcore-tph\Program.cs:строка 5
at Program.(String[] args)
Запрос:
await context.BaseChildren
.Where(child => child.Base.Parent.ID == 1)
.ToListAsync();
Пакеты Nuget
Командная строка:
dotnet nuget add Microsoft.EntityFrameworkCore.Design
dotnet nuget add Microsoft.EntityFrameworkCore
dotnet nuget add Npgsql.EntityFrameworkCore.PostgreSQL
Менеджер пакетов
Install-Package Microsoft.EntityFrameworkCore.Design
Install-Package Microsoft.EntityFrameworkCore
Install-Package Npgsql.EntityFrameworkCore.PostgreSQL
Program.cs
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
using var context = new MyContext();
await context.BaseChildren
.Where(child => child.Base.Parent.ID == 123)
.ToListAsync();
public class MyContext : DbContext
{
public DbSet
Parents { get; set; }
public DbSet D1s { get; set; }
public DbSet D2s { get; set; }
public DbSet BaseChildren { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseNpgsql(@"Host=localhost;Username=postgres;Password=password;Database=mydatabase");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity()
.HasDiscriminator("type")
.HasValue("base")
.HasValue("d1")
.HasValue("d2");
}
}
public class Parent
{
public int ID { get; set; }
public List D1s { get; set; }
public List D2s { get; set; }
}
public abstract class Base
{
public int ID { get; set; }
public string Url { get; set; }
public int ParentId { get; set; }
[ForeignKey(nameof(ParentId))]
public Parent Parent { get; set; }
public List Children { get; set; }
}
public class BaseChild
{
public int ID { get; set; }
public string Property { get; set; }
public int BaseId { get; set; }
[ForeignKey(nameof(BaseId))]
public Base Base { get; set; }
}
public class D1 : Base
{
public string D1Property { get; set; }
}
public class D2 : Base
{
public string D2Property { get; set; }
}
РЕДАКТИРОВАТЬ: я понимаю альтернативы, но хотел бы знать, почему объект не может определить сопоставление между BaseChild и Base.
То, что у меня есть, работает, если я пишу запрос, подобный приведенному ниже, поэтому я хотел бы понять, почему он не работает в обратном порядке. Я могу предположить, почему это не так, но я ищу окончательный ответ и, возможно, некоторую документацию. Ничто из того, что я нашел, не является столь глубоким, как приведенный мной пример.
await context.Parents
.Include(p => p.D1s)
.ThenInclude(d1 => d1.Children)
.Include(p => p.D2s)
.ThenInclude(d2 => d2.Children)
.ToListAsync();