Как запросить представление с коллекцией дочерних таблиц?

Я хочу запросить представление с коллекцией дочерних таблиц в EF Core 3.1. Возьмите мой упрощенный пример с 3 таблицами:

public class Relation
{
    public long Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class Invoice
{
    public long Id { get; set; }
    public string Reference { get; set; }

    public long RelationId { get; set; }
    public virtual Relation Relation { get; set; }

    public virtual ICollection<InvoiceLine> InvoiceLines { get; set; } = new HashSet<InvoiceLine>();
}

public class InvoiceLine
{
    public long Id { get; set; }
    public decimal Amount { get; set; }
    public decimal Price { get; set; }
    public string ArticleReference { get; set; }

    public long InvoiceId { get; set; }
    public virtual Invoice Invoice { get; set; }
}

Я добавляю представление SQL в свою миграцию:

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.Sql(@"
        CREATE OR ALTER VIEW dbo.InvoiceOverview
        AS
        SELECT 
            i.Id
            ,i.Reference
            ,r.FistName + ' ' + r.LastName as Name
        FROM dbo.Invoices i
        INNER JOIN Relations r ON r.Id = i.RelationId");
}

Модель InvoiceView + конфигурация

public class InvoiceView
{
    public long Id { get; set; }
    public string Reference { get; set; }
    public string Name { get; set; }
}

public void Configure(EntityTypeBuilder<InvoiceOverview> builder)
{
    builder.HasKey(_ => _.Id);
    builder.ToView("InvoiceOverview");
}

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

Context.InvoiceOverview.AsNoTracking().AsQueryable().Where(_ =>
    _.InvoiceLines.Select(invoiceLine => invoiceLine.ArticleReference)
        .Any(articleReference => articleReference == "Test").ToListAsync();

Я добавил InvoiceLine-collection в модель InvoiceOverview и обновил config.

public class InvoiceView
{
    public long Id { get; set; }
    public string Reference { get; set; }
    public string Name { get; set; }

    public virtual ICollection<InvoiceLine> InvoiceLines { get; set; }
}

public void Configure(EntityTypeBuilder<InvoiceOverview> builder)
{
    builder.HasKey(_ => _.Id);
    builder.ToView("InvoiceOverview");

    builder.HasMany(_ => _.InvoiceLines)
        .WithOne()
        .HasForeignKey(_ => _.InvoiceId);
}

С приведенной выше конфигурацией я успешно могу выполнить запрос. Единственная проблема, с которой я сейчас сталкиваюсь, заключается в том, что когда я запускаю «Add-Migration», они хотят создать внешний ключ. Невозможно создать внешний ключ для представления (а внешний ключ уже существует в таблице, используемой в представлении).

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.AddForeignKey(
        name: "FK_InvoiceLines_InvoiceOverview_InvoiceId",
        table: "InvoiceLines",
        column: "InvoiceId",
        principalTable: "InvoiceOverview",
        principalColumn: "Id",
        onDelete: ReferentialAction.Cascade);
}

Можно ли явно игнорировать внешний ключ при создании сценария миграции или мне следует написать свою конфигурацию по-другому?


person Boomit    schedule 08.10.2020    source источник


Ответы (1)


Я нашел решение в Entity Framework Core 2.2. Отключить перенос для определенных объектов

public void Configure(EntityTypeBuilder<InvoiceOverview> builder)
{
    builder.HasKey(_ => _.Id);
    builder.ToView("InvoiceOverview");

    builder.HasMany(_ => _.InvoiceLines)
        .WithOne()
        .HasForeignKey(_ => _.InvoiceId);

    if (MigrationHelper.IsMigrationOperationExecuting())
    {
        builder.Ignore(x => x.InvoiceLines);
    }
}

public static class MigrationHelper
{
    public static bool IsMigrationOperationExecuting()
    {
        var commandLineArguments = Environment.GetCommandLineArgs();
        string[] orderedMigrationArguments = { "migrations", "add" };

        for (var i = 0; i <= commandLineArguments.Length - orderedMigrationArguments.Length; i++)
        {
            if (commandLineArguments.Skip(i).Take(orderedMigrationArguments.Length).SequenceEqual(orderedMigrationArguments))
                return true;
        }

        return false;
    }
}
person Boomit    schedule 12.10.2020