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ímBlog.Posts
navigační vlastnosti.AuditEntry
vzhledem k tomu, že je zadán vOnModelCreating
.
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");
});
}
}