Nie ładuje się nawigacja w formularzu

0

Cześć,

Próbuję zapisać do bazy złożony model składający się z dwóch kluczy obcych:
Poniższy kod czyta pola z formularza i tworzy model danych.

public AccountingDocumentModel Document
{
    get
    {
        return new AccountingDocumentModel()
        {
            Id = DocumentId,
            TypeOfAccountingDocument = cmbRodzajDokumentu.SelectedItem.ToString(),
            IdNumber = tbNumer.Text,
            KontrahentId = Kontrahent.Id,
            OperationDescription = tbOpisOperacji.Text,
            OperationValue = Convert.ToDouble(tbWartosc.Text),
            OperationDate = Convert.ToDateTime(dpDataOperacji.Text),
            SaleRecord = SaleRecords,
            KPiREntries = new KPiREntryModel()
            {
                KPiRId = AppSettings.SelectedKPiR.Id
            }
        };
    }
}

Następnie wywołuje funkcję zapisującą do bazy i wykonuję następujący kod:

public static void SaveDocument(AccountingDocumentModel document)
{
    using (var ctx = new LocalSQLContext())
    {
        if (document.Id != 0)
            ctx.AccountingDocuments.Update(document);
        else
            ctx.AccountingDocuments.Add(document);

        ctx.SaveChanges();
    }
}

Model wygląda następująco:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Windows.Documents;

namespace KPiR.Data.Models
{
    public class AccountingDocumentModel
    {
        [Key]
        public int Id { get; set; }
        [Required, StringLength(50)]
        public string TypeOfAccountingDocument { get; set; }
        [Required, StringLength(50)]
        public string IdNumber { get; set; }
        public int ContractorId { get; set; }
        [Required, StringLength(8000)]
        public string OperationDescription { get; set; }
        public double OperationValue { get; set; }
        [DataType(DataType.Date)]
        public DateTime OperationDate { get; set; }

        public ContractorModel Kontrahent { get; set; }
        public List<SaleRecordsModel> SaleRecord { get; set; }
        public KPiREntryModel KPiREntries { get; set; }
    }
}

Relacje wyglądają następująco:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<AccountingDocumentModel>()
        .HasOne(x => x.Kontrahent)
        .WithMany(x => x.Documents)
        .HasForeignKey(x => x.ContractorId);

    modelBuilder.Entity<KPiREntryModel>()
        .HasOne(x => x.KPiR)
        .WithMany(x => x.KPiREntries)
        .HasForeignKey(x => x.KPiRId);

    modelBuilder.Entity<KPiREntryModel>()
        .HasOne(x => x.AccountingDocument)
        .WithOne(x => x.KPiREntries);

    modelBuilder.Entity<SaleRecordsModel>()
        .HasOne(x => x.AccountingDocument)
        .WithMany(x => x.SaleRecord)
        .HasForeignKey(x => x.AccountingDocumentId);
}

Kod wykonuje się poprawnie i zapisuje dane i klucze obce do bazy. Natomiast, gdy próbuję czytać dane z bazy to otrzymuje błąd:
screenshot-20221225225602.png
Nie rozumiem czemu EF nie wczytał nawigacji

3

Jak wygląda Twoja metoda GetDocuments?
Jeśli chcesz doczytać inne tabelki, to musisz dodać .Include().

W Twoim przypadku będzie to prawdopodobnie coś w stylu
await dbContext.AccountingDocumentModel.Include(x => x.Kontrahent).ToList()

0
froziu napisał(a):

Jak wygląda Twoja metoda GetDocuments?
Jeśli chcesz doczytać inne tabelki, to musisz dodać .Include().

W Twoim przypadku będzie to prawdopodobnie coś w stylu
await dbContext.AccountingDocumentModel.Include(x => x.Kontrahent).ToList()

GetDocuments wygląda następująco:

public static List<AccountingDocumentModel> GetDocuments()
{
    using (var ctx = new LocalSQLContext())
    {
        return ctx.AccountingDocuments.ToList();
    }
}

Teraz zamieniłem na:

public static List<AccountingDocumentModel> GetDocuments()
{
    using (var ctx = new LocalSQLContext())
    {
        return ctx.AccountingDocuments.Include(x => x.Kontrahent).Include(x => x.KPiREntries).ToList();
    }
}

Faktycznie teraz mapuje się poprawnie, ale z tego co kojarzę to EntityFramework sam przeprowadza mapowanie. W takim przypadku przy każdym pobraniu złożonych obiektów z bazy będzie trzeba ręcznie mapować obiekty. Czy jest może jakiś parametr, który automatycznie mapuje podobiekty?

3

Tu nie chodzi o mapowanie, tylko o join'a do drugiej tabeli. Jakbyś miał tych relacji więcej, a potrzebował dane tylko z jednej tabelki to chyba nie chciałbyś żeby ci pobierało dane których nie potrzebujesz? Każdy join wpływa na performance.

1

W bazie danych też tworzysz relacje, a jednak możesz dać
select * from accountingDocuments i pobierze Ci tylko accounting documents
a możesz dać
select * from accountingDocument join kontrahent on accountingDocument.Id = kontrahent.accountingDocumentId i dociągnąć kolejną tabelkę

Przy okazji jest coś takiego jak lazy/eager loading i o ile się nie mylę kiedyś było w EF tak, że jak odwoływałeś się do w Twoim przypadku obiektu kontrahent to przy każdej iteracji EF dociągał relacje kolejnym selectem (lazy loading). Wtedy co prawda nie było problemu z nullem, ale był tzw. problem select n+1.
Teraz robisz jawnie inlude (join'a) i masz wszystko to co chcesz dociągnięte (o ile chcesz, bo Ty tutaj masz obecnie nad tym kontrolę poprzez wywołanie lub nie include'a)

1 użytkowników online, w tym zalogowanych: 0, gości: 1