EF Core отображение один-ко-многим в таблицы без ключей - PullRequest
0 голосов
/ 28 февраля 2020

Я пытаюсь сопоставить таблицы из старой IBM Db2 базы данных с сущностями, использующими EntityFramework Core 2.2, но у этих таблиц нет никаких ключей вообще (да, я тоже был в шоке), и я не уверен, что я ' Я даже позволил добавить их к этому древнему зверю, который бегал со времен каменного века.

До сих пор у меня были вещи для работы, путем обратного проектирования отношений и поиска потенциальных ключей для использования, чтобы 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();

Спасибо!

Ответы [ 2 ]

0 голосов
/ 02 марта 2020

Решено! Проблема заключалась в том, что геттеры свойств сущности обрезали поле:

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);, тогда это также будет работать правильно.

Я удалил обрезку (и частные поля) и сделал обрезку, используя AutoMapper на уровне DTO следующим образом: CreateMap<string, string>().ConvertUsing((s, d) => s.Trim());

Теперь я всегда получаю 3 результата, как и должен, независимо от того, сколько раз я перечисляю IQueryable.

0 голосов
/ 28 февраля 2020

Вы не можете использовать «Включить» linq без ключа / отношения в Db2.

Вы должны использовать ниже

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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...