I'm trying to map tables from an old IBM Db2
database to entities using EntityFramework Core 2.2
but these tables don't have any keys at all (yes I was shocked too) and I'm not sure if I'm even allowed add them to this ancient beast that has been running since the stone age.
So far I've gotten things to work by reverse engineering the relationships and finding potential keys to use so that EF can happily track these entities, but I'm facing an issue with a one-to-many mapping.
I want to make a one-to-many mapping from the Invoice
table to the SellerAccountDetails
table. My configuration:
Invoice entity:
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 entity:
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
});
}
}
Now this works when I make a query and then call ToList()
, in my test code I'm supposed to get 3 SellerAccountDetails
entities for one Finvoice
, but if I don't materialize the IQueryable
, I get 6 SellerAccountDetails
for one Finvoice
, and if I enumerate again, they increase to 9, and so on...
Shouldn't EF know from the configured primary key on SellerAccountDetails
what makes this entity unique?
I added the HasPrincipalKey
because the property SellerPartyIdentifier
(from Finvoice) corresponds to the property SellerAccountPartyIdentifier
on the accounts table, but it's not a primary key. If I remove it and keep just the 2 foreign keys, the result is the same.
How do I make this work? I might be missing something obvious here, but I don't see it.
Here's my example query:
var invoices = _dbContext.Invoices.Include(i => i.SellersAccountDetails).ThenInclude(s => s.Invoice).
Where(i => i.FinvoiceBatchNumber == 13491).OrderBy(i => i.FinvoiceBatchRowNumber).Take(1);//.ToList();
Thank you!
You cannot use "Include" linq without key/relationship in Db2.
You have to use below
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);
Solved! The problem was that the entity properties' getters were trimming the field:
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; }
}
For some reason this was confusing the EF tracker, because if I also disable tracking by using AsNoTracking
(or setting it globally by doing optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
then it would also work correctly.
I removed the trim (and the private fields), and did the trimming using AutoMapper
on the DTO level like so: CreateMap<string, string>().ConvertUsing((s, d) => s.Trim());
Now I always get 3 results as I should no matter how many times I enumerate the IQueryable.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.