Typy entit

Zahrnutí dbSet typu do kontextu znamená, že je součástí modelu EF Core; Tento typ obvykle označujeme jako entitu. EF Core může číst a zapisovat instance entit z/do databáze a pokud používáte relační databázi, EF Core může vytvářet tabulky pro vaše entity prostřednictvím migrací.

Zahrnutí typů do modelu

Podle konvence jsou typy vystavené ve vlastnostech DbSet ve vašem kontextu zahrnuty do modelu jako entity. Zahrnuté jsou také typy entit zadané v OnModelCreating metodě, stejně jako všechny typy nalezené rekurzivně prozkoumáním navigačních vlastností jiných zjištěných typů entit.

V ukázce kódu níže jsou zahrnuty všechny typy:

  • Blog je zahrnuta, protože je zpřístupněna ve vlastnosti DbSet v kontextu.
  • Post je zahrnuta, protože je zjištěna prostřednictvím Blog.Posts navigační vlastnosti.
  • AuditEntry vzhledem k tomu, že je zadán v OnModelCreating.
internal class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<AuditEntry>();
    }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public Blog Blog { get; set; }
}

public class AuditEntry
{
    public int AuditEntryId { get; set; }
    public string Username { get; set; }
    public string Action { get; set; }
}

Vyloučení typů z modelu

Pokud nechcete, aby byl typ součástí modelu, můžete ho vyloučit:

[NotMapped]
public class BlogMetadata
{
    public DateTime LoadedFromDatabase { get; set; }
}

Vyloučení z migrací

Někdy je užitečné mít stejný typ entity namapovaný ve více DbContext typech. To platí zejména při použití ohraničených kontextů, pro které je běžné mít pro každý ohraničený kontext jiný DbContext typ.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<IdentityUser>()
        .ToTable("AspNetUsers", t => t.ExcludeFromMigrations());
}

Při této migraci konfigurace se tabulka nevytvoří AspNetUsers , ale IdentityUser stále je součástí modelu a dá se použít normálně.

Pokud potřebujete tabulku znovu spravovat pomocí migrací, měla by se vytvořit nová migrace, kde AspNetUsers není vyloučena. Další migrace teď bude obsahovat všechny změny provedené v tabulce.

Název tabulky

Podle konvence se každý typ entity nastaví tak, aby se mapovat na tabulku databáze se stejným názvem jako vlastnost DbSet, která zpřístupňuje entitu. Pokud pro danou entitu neexistuje žádná sada DbSet, použije se název třídy.

Název tabulky můžete nakonfigurovat ručně:

[Table("blogs")]
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
}

Schéma tabulky

Při použití relační databáze se tabulky vytvářejí podle konvence vytvořené ve výchozím schématu vaší databáze. Například Microsoft SQL Server použije dbo schéma (SQLite nepodporuje schémata).

Tabulky, které se mají vytvořit v určitém schématu, můžete nakonfigurovat následujícím způsobem:

[Table("blogs", Schema = "blogging")]
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
}

Místo zadávání schématu pro každou tabulku můžete také definovat výchozí schéma na úrovni modelu pomocí rozhraní FLUENT API:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.HasDefaultSchema("blogging");
}

Všimněte si, že nastavení výchozího schématu ovlivní také jiné databázové objekty, například sekvence.

Zobrazení mapování

Typy entit je možné mapovat na zobrazení databáze pomocí rozhraní Fluent API.

Poznámka

Ef předpokládá, že odkazované zobrazení již v databázi existuje, nevytvoří ho automaticky při migraci.

modelBuilder.Entity<Blog>()
    .ToView("blogsView", schema: "blogging");

Mapování na zobrazení odebere výchozí mapování tabulky, ale typ entity lze také namapovat na tabulku explicitně. V takovém případě se mapování dotazů použije pro dotazy a mapování tabulky se použije pro aktualizace.

Tip

Pokud chcete otestovat typy entit bez klíčů mapované na zobrazení pomocí zprostředkovatele v paměti, namapujte je na dotaz prostřednictvím ToInMemoryQuery. Další informace najdete v dokumentaci k poskytovateli paměti.

Mapování funkcí s hodnotami tabulky

Je možné mapovat typ entity na funkci s hodnotou tabulky (TVF) místo tabulky v databázi. Abychom to mohli ilustrovat, nadefinujme jinou entitu, která představuje blog s více příspěvky. V příkladu je entita bez klíče, ale nemusí být.

public class BlogWithMultiplePosts
{
    public string Url { get; set; }
    public int PostCount { get; set; }
}

Dále v databázi vytvořte následující funkci s hodnotou tabulky, která vrací pouze blogy s více příspěvky a počet příspěvků přidružených k jednotlivým blogům:

CREATE FUNCTION dbo.BlogsWithMultiplePosts()
RETURNS TABLE
AS
RETURN
(
    SELECT b.Url, COUNT(p.BlogId) AS PostCount
    FROM Blogs AS b
    JOIN Posts AS p ON b.BlogId = p.BlogId
    GROUP BY b.BlogId, b.Url
    HAVING COUNT(p.BlogId) > 1
)

Teď můžete entitu BlogWithMultiplePosts namapovat na tuto funkci následujícím způsobem:

modelBuilder.Entity<BlogWithMultiplePosts>().HasNoKey().ToFunction("BlogsWithMultiplePosts");

Poznámka

Aby bylo možné namapovat entitu na funkci s hodnotou tabulky, musí být funkce bez parametrů.

Obvykle se vlastnosti entity mapují na odpovídající sloupce vrácené TVF. Pokud sloupce vrácené TVF mají jiné názvy než vlastnost entity, lze sloupce entity nakonfigurovat pomocí HasColumnName metody, stejně jako při mapování na běžnou tabulku.

Pokud je typ entity namapován na funkci s hodnotou tabulky, dotaz:

var query = from b in context.Set<BlogWithMultiplePosts>()
            where b.PostCount > 3
            select new { b.Url, b.PostCount };

Vytvoří následující SQL:

SELECT [b].[Url], [b].[PostCount]
FROM [dbo].[BlogsWithMultiplePosts]() AS [b]
WHERE [b].[PostCount] > 3

Komentáře k tabulce

Můžete nastavit libovolný textový komentář, který se nastaví v tabulce databáze, což vám umožní dokumentovat schéma v databázi:

[Comment("Blogs managed on the website")]
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
}

Typy entit sdíleného typu

Typy entit, které používají stejný typ CLR, se označují jako typy entit sdíleného typu. Tyto typy entit musí být nakonfigurovány s jedinečným názvem, který musí být zadán při každém použití typu entity sdíleného typu kromě typu CLR. To znamená, že odpovídající DbSet vlastnost musí být implementována Set pomocí volání.

internal class MyContext : DbContext
{
    public DbSet<Dictionary<string, object>> Blogs => Set<Dictionary<string, object>>("Blog");

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.SharedTypeEntity<Dictionary<string, object>>(
            "Blog", bb =>
            {
                bb.Property<int>("BlogId");
                bb.Property<string>("Url");
                bb.Property<DateTime>("LastUpdated");
            });
    }
}