EF, Code First, vazba Many - Many   otázka

Entity Framework

Dobrý den,

měl bych dotaz ohledně EF Code First a vazby Many-Many na SQL Compact databázi.

S touto technologií teprve začínám, a tak možná dělám nějakou začátečnickou chybu.

Vytvořil jsem si model př.:

class RowBase
{
    public ICollection<GCode> GCodes { get; set; }
}

class GCode
{
    public virtual ICollection<RowBase> Rows { get; set; }
}

po vytvoření příslušné instance DbContext se vytvoří tabulky v databázi, včetně číselníku pro vazbu many-many (GCodeRowBases)

Vytvořím si objekty GCode a vložím je do tabulky GCodes a stejným způsobem vytvořím RowBase a vložím ho do tabulky Rows.

Po uložení změn, data v tabulkách jsou - OK, číselník je zatím prázdný.

Najdu si v contextu objekt RowBase a do kolekce mu přiřadím všechny objekty GCode. V číselníku GCodeRowBases se objeví napárování indexů tabulek - Také OK.

Pokud si ale nyní dám zobrazit kolekci Gcodes v objektu RowBase tak mi stále vrací null.

Myslím si, že jsem někde nepochopil systém pro vytváření vazeb mezi jednotlivými tabulkami.

Mohl by mi někdo poradit jak správně vložit a přečíst položky u vazby many-many v code first ?

Děkuji

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Zkuste tu kolekci taky udělat virtuální, ono to může být tím, že na nevirtuálních nemůže fungovat lazy loading.

Jak přesně ten objekt vytahujete z databáze?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

virtual zkusím,

dotazuji se LINQ to Object,

Vytažení konkrétního řádku

using (var dc = new EFDataContext())
var row = (from r in dc.Rows
           where r.Number == 10
           select r).Single();

//ověření, že mám vysledek i když single by to měl shodit pokud by tam nebylo nic
Debug.Print(row.ToString());

//GCody z řádku - vrací vždy null
var g = row.GCodes;

V tabulkách data ovšem jsou.

K hashovací tabulce kde jsou čísla RowId a GCodeId nemám přístup, code first mi nevytvoří příslušný objekt. Kvůli tomu bych to chtěl využít.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Tak jsem zase neuspěl.

Dotaz jak si představuju, že měl fungovat:


var doc = (from d in dc.Documents
           where d.Name == "TestDocument"
           select d).Single();

var row = (from r in dc.Rows
           select r).First();
//row se ale nevykoná, protože v dokumentu kolekce Rows je prázdná.

return row.GCodes.ToList();

Přikládám celý testovací projekt.

Tabulky GCodes a MCodes, jsou plněny SQL dávkou mimo aplikaci.

Modelové třídy:

class Document
    {

        [Key]
        public int DocumentId { get; set; }

        [Required, StringLength(50)]
        public string Name { get; set; }

        [StringLength(200)]
        public string Description { get; set; }

        [Required]
        public DateTime Created { get; set; }

        [Required]
        public DateTime Saved { get; set; }

        public virtual ICollection<Row> Rows { get; set; }

        public Document()
        {
            Rows = new HashSet<Row>();
        }

    }

class Row
    {

        [Key]
        public int RowId { get; set; }

        public Single? X { get; set; }
        public Single? Y { get; set; }
        public Single? Z { get; set; }
        public Single? A { get; set; }
        public Single? B { get; set; }
        public Single? C { get; set; }
        public Single? I { get; set; }
        public Single? J { get; set; }
        public int? T { get; set; }
        public int? F { get; set; }
        public int? S { get; set; }

        [StringLength(50)]
        public string Comment { get; set; }

        [Required]
        public int RowNumber { get; set; }

        public int DocumentId { get; set; }
        public virtual Document Document { get; set; }
        public virtual ICollection<MCode> MCodes { get; set; }
        public virtual ICollection<GCode> GCodes { get; set; }

        public Row()
        {
            MCodes = new HashSet<MCode>();
            GCodes = new HashSet<GCode>();
        }

    }

class GCode
    {

        [Key]
        public int GCodeId { get; set; }
        
        [Required]
        public int Number { get; set;}

        [StringLength(50)]
        public string Comment { get; set; }

        [StringLength(200)]
        public string Description { get; set; }

        [Required]
        public bool Used { get; set; }

        public virtual ICollection<Row> Rows { get; set; }

        public GCode()
        {
            Rows = new HashSet<Row>();
        }

    }

class MCode
    {

        [Key]
        public int MCodeId { get; set; }

        [Required]
        public int Number { get; set;}

        [StringLength(50)]
        public string Comment { get; set; }
        
        [StringLength(200)]
        public string Description { get; set; }

        [Required]
        public bool Used { get; set; }

        public virtual ICollection<Row> Rows { get; set; }

        public MCode()
        {
            Rows = new HashSet<Row>();
        }

    }

 class CmsContext: DbContext
    {

        public CmsContext()
            : base(nameOrConnectionString: "ProgramDatabaseEntities")
        {}

        public DbSet<Document> Documents { get; set; }

        public DbSet<Row> Rows { get; set; }

        public DbSet<GCode> GCodes { get; set; }

        public DbSet<MCode> MCodes { get; set; }

    }

Přidání testovacího dokumentu:

        private static void AddTestDocument(Data.CmsContext dc)
        {

            var doc = new Data.Document
            {
                Name = "TestDocument",
                Created = DateTime.Now,
                Saved = DateTime.Now,
                Description = "popis",
            };

            dc.Documents.Add(doc);

            dc.SaveChanges();

        }

Přidání testovacích řádků:

        private static void AddTestRow(Data.CmsContext dc)
        {

            var doc = (from d in dc.Documents
                where d.Name == "TestDocument"
                select d).Single();

            var g00 = (from g in dc.GCodes
                where g.Number == 0
                select g).Single();

            var g01 = (from g in dc.GCodes
                where g.Number == 1
                select g).Single();

            var g90 = (from g in dc.GCodes
                where g.Number == 90
                select g).Single();

            var g91 = (from g in dc.GCodes
                where g.Number == 91
                select g).Single();

            var m3 = (from m in dc.MCodes
                where m.Number == 3
                select m).Single();

            var m8 = (from m in dc.MCodes
                where m.Number == 8
                select m).Single();
            

            var r1 = new Row
            {
                X = 1000,
                Y = 500,
                Z = 600,
                Document = doc,
                RowNumber = 10,
                Comment = "Komentář",
                MCodes = new HashSet<MCode>(),
                GCodes = new HashSet<GCode>(),
                T = 5,
            };

            r1.MCodes.Add(m3);
            r1.MCodes.Add(m8);
            r1.GCodes.Add(g00);
            r1.GCodes.Add(g90);

            var r2 = new Row
            {
                A = 600,
                B = 350,
                Document = doc,
                C = 658.98F,
                RowNumber = 20,
                Comment = "Komentář",
                T = 5,
                MCodes = new HashSet<MCode>(),
                GCodes = new HashSet<GCode>()
            };

            r2.MCodes.Add(m3);
            r2.MCodes.Add(m8);
            r2.GCodes.Add(g01);
            r2.GCodes.Add(g91);

            dc.Rows.Add(r1);
            dc.Rows.Add(r2);

        }
nahlásit spamnahlásit spam 0 odpovědětodpovědět

Pokud chcete pouzit lazy loading, navigacni property musi byt virtual (coz mate).


var doc = dc.Documents.Single(x => x.Name == "TestDocument");
var row = doc.Rows.First();
var gCodes = row.GCodes.ToList();

Pokud nechcete lazy loading ...

var doc = dc.Documents.Include("Rows").Include("Rows.GCodes").Single(x => x.Name == "TestDocument");
var row = doc.Rows.First();
var gCodes = row.GCodes.ToList();

:x

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Dobrý den,

děkuji za odpověď.

Pokud použiji příklad, který jste napsal bez lazy loadingu, tak ten funguje jak má.

Při debugu v doc objektu jsou kolekce s řádky a v nich gcody naplněny.

Pokud použiji příklad s lazy. Tak ten nefunguje, object doc se sice z db vytáhne, ale kolekce row má 0 prvků. Pokud si vytáhnu jeden řádek (row) tak má opět 0 objektů gcode.

Proč mi lazy nefunguje ?

Jen pro info, NuGety mám:

EntityFramework 6.1.0

EntityFramework.SqlServerCompact 6.1.0

Microsoft SQL Server Compact Edition 4.0.8854.1

S EF jsem kdysi pracoval na plnohodnotném SQL s DbFirst a tam lazy fungoval.

Tak z toho usuzuji jestli není problém v té Compact edici SQL ?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Napada me jeste vyzkouset zapnout explicitne LazyLoading.

Jeslti je problem v Compact edici SQL to netusim, nikdy jsem ji nepouzival.

Rekl bych ze to bude ale spis zalezitost EF.

   using (var dc = new EFDataContext()) 
   {
       dc.Configuration.LazyLoadingEnabled = true;
   
       // ....
       // ....
       // ....
   }
   
nahlásit spamnahlásit spam 0 odpovědětodpovědět

Koukal jsem se a LazyLoadingEnabled je defaultně true.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Vyzkousejte jeste nastaveni virtual v Context tride.

       public virtual DbSet<Document> Documents { get; set; }
 
       public virtual DbSet<Row> Rows { get; set; }
 
       public virtual DbSet<GCode> GCodes { get; set; }
 
       public virtual DbSet<MCode> MCodes { get; set; }
nahlásit spamnahlásit spam 0 odpovědětodpovědět

Pro jistotu jsem smazal celou databázi. Změnil Context jak píšete.

A nechal ji celou vytvořit znovu.

Ovšem žádná změna - bez lazy to šlape, s lazy ne.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

No a ještě mě tak napadlo, jestli to není použitím Compact SQL 4.0 ?

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback