Sdílet prostřednictvím


Relace, vlastnosti navigace a cizí klíče

Tento článek obsahuje přehled toho, jak Entity Framework spravuje vztahy mezi entitami. Poskytuje také pokyny k mapování a manipulaci s relacemi.

Relace v EF

V relačních databázích se relace (označované také jako asociace) mezi tabulkami definují prostřednictvím cizích klíčů. Cizí klíč (FK) je sloupec nebo kombinace sloupců, které slouží k vytvoření a vynucení propojení mezi daty ve dvou tabulkách. Obecně existují tři typy relací: 1:1, 1:N a M:N. V relaci 1:N je cizí klíč definován v tabulce, která představuje mnoho konce relace. Relace M:N zahrnuje definování třetí tabulky (označované jako tabulka spojení nebo spojení), jejíž primární klíč se skládá z cizích klíčů z obou souvisejících tabulek. V relaci 1:1 primární klíč funguje navíc jako cizí klíč a pro žádnou tabulku neexistuje žádný samostatný sloupec cizího klíče.

Následující obrázek ukazuje dvě tabulky, které se účastní relace 1:N. Tabulka Course je závislá tabulka, protože obsahuje sloupec Id oddělení , který ji propojuje s tabulkou Oddělení .

Department and Course tables

V Entity Frameworku může entita souviset s jinými entitami prostřednictvím přidružení nebo relace. Každá relace obsahuje dva konce, které popisují typ entity a násobnost typu (jedna, nula nebo jedna nebo mnoho) pro tyto dvě entity v dané relaci. Relace může být řízena referenčním omezením, které popisuje, který konec relace je hlavní rolí a která je závislá role.

Navigační vlastnosti poskytují způsob, jak procházet přidružení mezi dvěma typy entit. Každý objekt může mít navigační vlastnost pro každou relaci, do které se účastní. Navigační vlastnosti umožňují procházet a spravovat relace v obou směrech a vracet buď objekt odkazu (pokud je násobnost jedna nebo nula nebo jedna), nebo kolekci (pokud je násobnost mnoho). Můžete také zvolit jednosměrnou navigaci, v takovém případě definujete navigační vlastnost pouze u jednoho z typů, které se účastní relace, a ne na obou.

Do modelu, který se mapuje na cizí klíče v databázi, se doporučuje zahrnout vlastnosti. Při zahrnutí vlastností cizího klíče můžete vytvořit nebo změnit relaci úpravou hodnoty cizího klíče u závislého objektu. Tento druh asociace se nazývá přidružení cizího klíče. Použití cizích klíčů je ještě důležitější při práci s odpojenými entitami. Všimněte si, že při práci s 1:1 nebo 1:0. 1 relace, neexistuje žádný samostatný sloupec cizího klíče, vlastnost primárního klíče funguje jako cizí klíč a je vždy zahrnuta v modelu.

Pokud sloupce cizího klíče nejsou součástí modelu, informace o přidružení se spravují jako nezávislý objekt. Relace se sledují prostřednictvím odkazů na objekt místo vlastností cizího klíče. Tento typ přidružení se nazývá nezávislé přidružení. Nejběžnější způsob, jak upravit nezávislé přidružení, je upravit navigační vlastnosti, které jsou generovány pro každou entitu, která se účastní přidružení.

V modelu můžete použít jeden nebo oba typy přidružení. Pokud ale máte čistou relaci M:N, která je propojená tabulkou spojení, která obsahuje pouze cizí klíče, ef použije nezávislé přidružení ke správě takové relace M:N.   

Následující obrázek znázorňuje koncepční model, který byl vytvořen pomocí Návrháře entity Framework. Model obsahuje dvě entity, které se účastní relace 1:N. Obě entity mají navigační vlastnosti. Kurz je závislá entita a má definovanou vlastnost cizího klíče DepartmentID .

Department and Course tables with navigation properties

Následující fragment kódu ukazuje stejný model, který byl vytvořen pomocí Code First.

public class Course
{
  public int CourseID { get; set; }
  public string Title { get; set; }
  public int Credits { get; set; }
  public int DepartmentID { get; set; }
  public virtual Department Department { get; set; }
}

public class Department
{
   public Department()
   {
     this.Courses = new HashSet<Course>();
   }  
   public int DepartmentID { get; set; }
   public string Name { get; set; }
   public decimal Budget { get; set; }
   public DateTime StartDate { get; set; }
   public int? Administrator {get ; set; }
   public virtual ICollection<Course> Courses { get; set; }
}

Konfigurace nebo mapování relací

Zbývající část této stránky popisuje, jak přistupovat k datům pomocí relací a manipulovat s nimi. Informace o nastavení relací v modelu najdete na následujících stránkách.

Vytváření a úpravy relací

Při přidružení cizího klíče při změně relace stav závislého objektu EntityState.Unchanged se změní na EntityState.Modified. Při nezávislé relaci změna relace neaktualizuje stav závislého objektu.

Následující příklady ukazují, jak pomocí vlastností cizího klíče a navigačních vlastností přidružit související objekty. S přidruženími cizích klíčů můžete použít metodu ke změně, vytvoření nebo úpravě relací. U nezávislých přidružení nelze použít vlastnost cizího klíče.

  • Přiřazením nové hodnoty k vlastnosti cizího klíče, jako v následujícím příkladu.

    course.DepartmentID = newCourse.DepartmentID;
    
  • Následující kód odebere relaci nastavením cizího klíče na hodnotu null. Všimněte si, že vlastnost cizího klíče musí být nullable.

    course.DepartmentID = null;
    

    Poznámka

    Pokud je odkaz v přidaném stavu (v tomto příkladu objektu kurzu), vlastnost navigace odkazu nebude synchronizována s klíčovými hodnotami nového objektu, dokud se nevolá SaveChanges. K synchronizaci nedojde, protože kontext objektu neobsahuje trvalé klíče pro přidané objekty, dokud nebudou uloženy. Pokud musíte mít nové objekty plně synchronizované, jakmile nastavíte relaci, použijte jednu z následujících metod.*

  • Přiřazením nového objektu k navigační vlastnosti. Následující kód vytvoří vztah mezi kurzem a znakem department. Pokud jsou objekty připojeny k kontextu, course je také přidán do department.Courses kolekce a odpovídající vlastnost cizího klíče objektu course je nastavena na hodnotu vlastnosti klíče oddělení.

    course.Department = department;
    
  • Chcete-li odstranit relaci, nastavte navigační vlastnost na nullhodnotu . Pokud pracujete s Entity Frameworkem, který je založený na rozhraní .NET 4.0, je potřeba před nastavením na hodnotu null načíst související konec. Příklad:

    context.Entry(course).Reference(c => c.Department).Load();
    course.Department = null;
    

    Počínaje entity Framework 5.0, která je založená na rozhraní .NET 4.5, můžete nastavit relaci na hodnotu null bez načtení souvisejícího konce. Aktuální hodnotu můžete také nastavit na hodnotu null pomocí následující metody.

    context.Entry(course).Reference(c => c.Department).CurrentValue = null;
    
  • Odstraněním nebo přidáním objektu v kolekci entit Do kolekce můžete například přidat objekt typu Course department.Courses . Tato operace vytvoří vztah mezi konkrétním kurzem a konkrétním department. Pokud jsou objekty připojeny k kontextu, odkaz oddělení a vlastnost cizího klíče objektu kurzu bude nastavena na odpovídající department.

    department.Courses.Add(newCourse);
    
  • ChangeRelationshipState Pomocí metody změnit stav zadané relace mezi dvěma objekty entity. Tato metoda se nejčastěji používá při práci s N-vrstvými aplikacemi a nezávislým přidružením (nedá se použít s přidružením cizího klíče). Chcete-li použít tuto metodu, musíte rozevírací seznam , ObjectContextjak je znázorněno v následujícím příkladu.
    V následujícím příkladu existuje vztah M:N mezi instruktory a kurzy. Zavoláním ChangeRelationshipState metody a předáním parametru EntityState.Added získáte SchoolContext informace o přidání relace mezi těmito dvěma objekty:

    
    ((IObjectContextAdapter)context).ObjectContext.
      ObjectStateManager.
      ChangeRelationshipState(course, instructor, c => c.Instructor, EntityState.Added);
    

    Upozorňujeme, že pokud aktualizujete relaci (nejen přidáváte), musíte po přidání nové relace odstranit starou relaci:

    ((IObjectContextAdapter)context).ObjectContext.
      ObjectStateManager.
      ChangeRelationshipState(course, oldInstructor, c => c.Instructor, EntityState.Deleted);
    

Synchronizace změn mezi cizími klíči a vlastnostmi navigace

Když změníte vztah objektů připojených k kontextu pomocí jedné z metod popsaných výše, Entity Framework musí udržovat cizí klíče, odkazy a kolekce synchronizované. Entity Framework automaticky spravuje tuto synchronizaci (označovanou také jako oprava relací) pro entity POCO s proxy servery. Další informace naleznete v tématu Práce s proxy servery.

Pokud používáte entity POCO bez proxy, musíte se ujistit, že DetectChanges metoda je volána k synchronizaci souvisejících objektů v kontextu. Všimněte si, že následující rozhraní API automaticky aktivují volání DetectChanges .

  • DbSet.Add
  • DbSet.AddRange
  • DbSet.Remove
  • DbSet.RemoveRange
  • DbSet.Find
  • DbSet.Local
  • DbContext.SaveChanges
  • DbSet.Attach
  • DbContext.GetValidationErrors
  • DbContext.Entry
  • DbChangeTracker.Entries
  • Spuštění dotazu LINQ na DbSet

V Entity Frameworku obvykle používáte navigační vlastnosti k načtení entit, které souvisejí s vrácenou entitou definovaným přidružením. Další informace naleznete v tématu Načítání souvisejících objektů.

Poznámka

Při přidružování cizího klíče při načtení souvisejícího konce závislého objektu se související objekt načte na základě hodnoty cizího klíče závislého, který je aktuálně v paměti:

    // Get the course where currently DepartmentID = 2.
    Course course = context.Courses.First(c => c.DepartmentID == 2);

    // Use DepartmentID foreign key property
    // to change the association.
    course.DepartmentID = 3;

    // Load the related Department where DepartmentID = 3
    context.Entry(course).Reference(c => c.Department).Load();

V nezávislém přidružení je související konec závislého objektu dotazován na základě hodnoty cizího klíče, která je aktuálně v databázi. Pokud však byla relace změněna a referenční vlastnost závislého objektu odkazuje na jiný objekt objektu, který je načten v kontextu objektu, Entity Framework se pokusí vytvořit relaci, jak je definována v klientovi.

Správa souběžnosti

V cizím i nezávislém přidružení jsou kontroly souběžnosti založené na klíčích entit a dalších vlastnostech entity, které jsou definovány v modelu. Pokud k vytvoření modelu použijete EF Designer, nastavte ConcurrencyMode atribut na pevný , aby bylo možné určit, že vlastnost má být zkontrolována pro souběžnost. Při použití Code First k definování modelu použijte poznámku ConcurrencyCheck k vlastnostem, které chcete zkontrolovat pro souběžnost. Při práci s Code First můžete také použít poznámku TimeStamp k určení, že vlastnost má být kontrolována pro souběžnost. V dané třídě můžete mít pouze jednu vlastnost časového razítka. Code First mapuje tuto vlastnost na pole bez hodnoty null v databázi.

Při práci s entitami, které se účastní kontroly souběžnosti a řešení, doporučujeme vždy používat přidružení cizího klíče.

Další informace najdete v tématu Zpracování konfliktů souběžnosti.

Práce s překrývajícími se klíči

Překrývající se klíče jsou složené klíče, ve kterých jsou některé vlastnosti v klíči také součástí jiného klíče v entitě. V nezávislém přidružení nelze mít překrývající se klíč. Pokud chcete změnit přidružení cizího klíče, které obsahuje překrývající se klíče, doporučujeme místo použití odkazů na objekt změnit hodnoty cizího klíče.