[英]EF Core one-to-many mapping to tables with no keys
我正在尝试使用EntityFramework Core 2.2
将旧IBM Db2
数据库中的表映射到实体,但这些表根本没有任何键(是的,我也感到震惊),我不确定是否允许添加这头自石器时代就开始奔跑的远古野兽。
到目前为止,我已经通过对关系进行逆向工程并找到要使用的潜在密钥来解决问题,以便 EF 可以愉快地跟踪这些实体,但是我面临着一对多映射的问题。
我想从Invoice
表到SellerAccountDetails
表进行一对多映射。 我的配置:
发票实体:
public class FinvoiceConfiguration : IEntityTypeConfiguration<Finvoice>
{
public void Configure(EntityTypeBuilder<Finvoice> builder)
{
// PK for Invoice
builder.HasKey(f => new { f.FinvoiceBatchNumber, f.FinvoiceBatchRowNumber });
// One-to-many to SellerAccountDetails table
builder.HasMany(f => f.SellersAccountDetails)
.WithOne(s => s.Invoice)
.HasForeignKey(s => new
{
s.FinvoiceBatchNumber,
s.FinvoiceBatchRowNumber,
s.SellerAccountPartyIdentifier
})
.HasPrincipalKey(f => new
{
f.FinvoiceBatchNumber,
f.FinvoiceBatchRowNumber,
f.SellerPartyIdentifier
});
}
}
SellerAccountDetails 实体:
public class SellerAccountDetailsConfiguration : IEntityTypeConfiguration<SellerAccountDetails>
{
public void Configure(EntityTypeBuilder<SellerAccountDetails> builder)
{
// PK for SellerAccountDetails
builder.HasKey(s => new
{
s.FinvoiceBatchNumber,
s.FinvoiceBatchRowNumber,
s.SellerAccountPartyIdentifier,
s.SellerAccountID // <-- Needed for uniqueness of this entity
});
// Many-to-one to Invoice table
builder.HasOne(s => s.Invoice)
.WithMany(i => i.SellersAccountDetails)
.HasForeignKey(s => new
{
s.FinvoiceBatchNumber,
s.FinvoiceBatchRowNumber,
s.SellerAccountPartyIdentifier
})
.HasPrincipalKey(f => new
{
f.FinvoiceBatchNumber,
f.FinvoiceBatchRowNumber,
f.SellerPartyIdentifier
});
}
}
现在,这个作品时,我做一个查询,然后调用ToList()
在我的测试代码,我应该拿到3个SellerAccountDetails
实体一个Finvoice
,但如果我不兑现的IQueryable
,我得到6个SellerAccountDetails
一个Finvoice
,如果我再次枚举,它们会增加到 9,依此类推……
EF 不应该从SellerAccountDetails
上配置的主键知道是什么使该实体独一无二?
我添加了HasPrincipalKey
因为属性SellerPartyIdentifier
(来自 Finvoice)对应于帐户表上的属性SellerAccountPartyIdentifier
,但它不是主键。 如果我删除它并只保留 2 个外键,结果是一样的。
我如何使这项工作? 我可能在这里遗漏了一些明显的东西,但我没有看到。
这是我的示例查询:
var invoices = _dbContext.Invoices.Include(i => i.SellersAccountDetails).ThenInclude(s => s.Invoice).
Where(i => i.FinvoiceBatchNumber == 13491).OrderBy(i => i.FinvoiceBatchRowNumber).Take(1);//.ToList();
谢谢!
您不能在 Db2 中使用没有键/关系的“包含”linq。
你必须在下面使用
var invoices = (from a in _dbContext.Invoices.Where(x => x.FinvoiceBatchNumber == 13491)
from b in _dbContext.SellersAccountDetails.Where(x => x.InvoiceId = a.Id).DefaultOrEmpty()
select a, b).Take(1);
解决了! 问题是实体属性的 getter 正在修剪该字段:
private string _sellerAccountID;
[Column("FV77A", TypeName = "char(35)")]
[Required, DefaultValue("")]
[MinLength(0), MaxLength(35)]
public string SellerAccountID
{
get { return _sellerAccountID.Trim(); } // <-- Trim() is the culprit
set { _sellerAccountID = value; }
}
出于某种原因,这会混淆 EF 跟踪器,因为如果我还通过使用AsNoTracking
禁用跟踪(或通过执行optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
全局设置它optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
那么它也可以正常工作。
我删除了修剪(和私有字段),并在 DTO 级别使用AutoMapper
进行修剪,如下所示: CreateMap<string, string>().ConvertUsing((s, d) => s.Trim());
现在,无论我枚举 IQueryable 多少次,我总是得到 3 个结果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.