如何查询带有子 table 集合的视图?
How to query a view with child table collection?
我想在 EF Core 3.1 中查询带有子 table 集合的视图。
以我的简化示例为例,其中包含 3 tables:
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 模型并更新了配置。
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' 时,他们想要创建一个外键。无法为视图创建外键(并且外键已经存在于视图中使用的 table 上)。
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddForeignKey(
name: "FK_InvoiceLines_InvoiceOverview_InvoiceId",
table: "InvoiceLines",
column: "InvoiceId",
principalTable: "InvoiceOverview",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
是否可以在生成迁移脚本时显式忽略外键,还是我应该以不同的方式编写配置?
我在
中找到了解决方案
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;
}
}
我想在 EF Core 3.1 中查询带有子 table 集合的视图。 以我的简化示例为例,其中包含 3 tables:
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 模型并更新了配置。
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' 时,他们想要创建一个外键。无法为视图创建外键(并且外键已经存在于视图中使用的 table 上)。
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddForeignKey(
name: "FK_InvoiceLines_InvoiceOverview_InvoiceId",
table: "InvoiceLines",
column: "InvoiceId",
principalTable: "InvoiceOverview",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
是否可以在生成迁移脚本时显式忽略外键,还是我应该以不同的方式编写配置?
我在
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;
}
}