EF Core 一对多映射到没有键的表
EF Core one-to-many mapping to tables with no keys
我正在尝试将 tables 从旧 IBM Db2
数据库映射到使用 EntityFramework Core 2.2
的实体,但这些 tables 根本没有任何键(是的,我也很震惊)而且我不确定我是否被允许将它们添加到这个自石器时代以来一直 运行 的古老野兽中。
到目前为止,我已经通过对关系进行逆向工程并找到要使用的潜在键来让 EF 可以愉快地跟踪这些实体,但我面临着一对多映射的问题。
我想建立从 Invoice
table 到 SellerAccountDetails
table 的一对多映射。我的配置:
发票实体:
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()
时,这会起作用,在我的测试代码中,我应该为一个 Finvoice
获得 3 个 SellerAccountDetails
个实体,但是如果我不要具体化 IQueryable
,我得到 6 SellerAccountDetails
一个 Finvoice
,如果我再次枚举,它们会增加到 9,依此类推...
EF 不应该从 SellerAccountDetails
上配置的主键知道是什么让这个实体独一无二?
我添加了 HasPrincipalKey
因为 属性 SellerPartyIdentifier
(来自 Finvoice)对应于帐户 table 上的 属性 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 中没有 key/relationship,则无法使用 "Include" 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 是 trimming 字段:
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);
全局设置它,那么它也可以正常工作。
我删除了 trim(和私有字段),并在 DTO 级别上使用 AutoMapper
进行了 trimming,如下所示:
CreateMap<string, string>().ConvertUsing((s, d) => s.Trim());
现在无论我枚举 IQueryable 多少次,我总是得到 3 个结果。
我正在尝试将 tables 从旧 IBM Db2
数据库映射到使用 EntityFramework Core 2.2
的实体,但这些 tables 根本没有任何键(是的,我也很震惊)而且我不确定我是否被允许将它们添加到这个自石器时代以来一直 运行 的古老野兽中。
到目前为止,我已经通过对关系进行逆向工程并找到要使用的潜在键来让 EF 可以愉快地跟踪这些实体,但我面临着一对多映射的问题。
我想建立从 Invoice
table 到 SellerAccountDetails
table 的一对多映射。我的配置:
发票实体:
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()
时,这会起作用,在我的测试代码中,我应该为一个 Finvoice
获得 3 个 SellerAccountDetails
个实体,但是如果我不要具体化 IQueryable
,我得到 6 SellerAccountDetails
一个 Finvoice
,如果我再次枚举,它们会增加到 9,依此类推...
EF 不应该从 SellerAccountDetails
上配置的主键知道是什么让这个实体独一无二?
我添加了 HasPrincipalKey
因为 属性 SellerPartyIdentifier
(来自 Finvoice)对应于帐户 table 上的 属性 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 中没有 key/relationship,则无法使用 "Include" 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 是 trimming 字段:
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);
全局设置它,那么它也可以正常工作。
我删除了 trim(和私有字段),并在 DTO 级别上使用 AutoMapper
进行了 trimming,如下所示:
CreateMap<string, string>().ConvertUsing((s, d) => s.Trim());
现在无论我枚举 IQueryable 多少次,我总是得到 3 个结果。