Typy jednostek
Uwzględnienie elementu DbSet typu w kontekście oznacza, że jest on uwzględniony w modelu platformy EF Core; zazwyczaj nazywamy taki typ jak jednostka. Program EF Core może odczytywać i zapisywać wystąpienia jednostek z/do bazy danych, a jeśli używasz relacyjnej bazy danych, program EF Core może tworzyć tabele dla jednostek za pośrednictwem migracji.
Dołączanie typów w modelu
Zgodnie z konwencją typy uwidocznione we właściwościach dbSet w kontekście są uwzględniane w modelu jako jednostki. Typy jednostek określone w metodzie OnModelCreating
są również uwzględniane, podobnie jak wszelkie typy, które są odnajdywane rekursywnie eksplorując właściwości nawigacji innych odnalezionych typów jednostek.
W poniższym przykładzie kodu uwzględniono wszystkie typy:
Blog
element jest uwzględniony, ponieważ jest uwidoczniony we właściwości DbSet w kontekście.Post
element jest uwzględniony, ponieważ został odnaleziony za pośrednictwemBlog.Posts
właściwości nawigacji.AuditEntry
ponieważ jest określony w plikuOnModelCreating
.
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; }
}
Wykluczanie typów z modelu
Jeśli nie chcesz, aby typ został uwzględniony w modelu, możesz go wykluczyć:
[NotMapped]
public class BlogMetadata
{
public DateTime LoadedFromDatabase { get; set; }
}
Wykluczanie z migracji
Czasami przydatne jest mapowanie tego samego typu jednostki w wielu DbContext
typach. Jest to szczególnie istotne w przypadku używania ograniczonych kontekstów, dla których często występuje inny DbContext
typ dla każdego ograniczonego kontekstu.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<IdentityUser>()
.ToTable("AspNetUsers", t => t.ExcludeFromMigrations());
}
W przypadku tych migracji konfiguracji nie zostanie utworzona AspNetUsers
tabela, ale IdentityUser
nadal jest uwzględniona w modelu i może być używana normalnie.
Jeśli musisz ponownie rozpocząć zarządzanie tabelą przy użyciu migracji, należy utworzyć nową migrację, w której AspNetUsers
nie zostanie wykluczona. Następna migracja będzie teraz zawierać wszelkie zmiany wprowadzone w tabeli.
Nazwa tabeli
Zgodnie z konwencją każdy typ jednostki zostanie skonfigurowany do mapowania na tabelę bazy danych o takiej samej nazwie jak właściwość DbSet, która uwidacznia jednostkę. Jeśli dla danej jednostki nie istnieje zestaw DbSet, używana jest nazwa klasy.
Możesz ręcznie skonfigurować nazwę tabeli:
[Table("blogs")]
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
Schemat tabeli
W przypadku korzystania z relacyjnej bazy danych tabele są tworzone zgodnie z konwencją w domyślnym schemacie bazy danych. Na przykład program Microsoft SQL Server będzie używać schematu dbo
(SQLite nie obsługuje schematów).
Tabele można skonfigurować do utworzenia w określonym schemacie w następujący sposób:
[Table("blogs", Schema = "blogging")]
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
Zamiast określać schemat dla każdej tabeli, można również zdefiniować domyślny schemat na poziomie modelu za pomocą płynnego interfejsu API:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("blogging");
}
Należy pamiętać, że ustawienie domyślnego schematu będzie również miało wpływ na inne obiekty bazy danych, takie jak sekwencje.
Wyświetlanie mapowania
Typy jednostek można mapować na widoki bazy danych przy użyciu interfejsu API Fluent.
Uwaga
Program EF zakłada, że widok, do którego odwołuje się odwołanie, już istnieje w bazie danych, nie utworzy go automatycznie w ramach migracji.
modelBuilder.Entity<Blog>()
.ToView("blogsView", schema: "blogging");
Mapowanie na widok spowoduje usunięcie domyślnego mapowania tabeli, ale typ jednostki można również zamapować do tabeli jawnie. W takim przypadku mapowanie zapytań będzie używane dla zapytań, a mapowanie tabeli będzie używane do aktualizacji.
Napiwek
Aby przetestować typy jednostek bez klucza mapowane na widoki przy użyciu dostawcy w pamięci, zamapuj je na zapytanie za pomocą metody ToInMemoryQuery. Aby uzyskać więcej informacji, zobacz dokumentację dostawcy w pamięci.
Mapowanie funkcji wartości tabeli
Można mapować typ jednostki na funkcję o wartości tabeli (TVF) zamiast tabeli w bazie danych. Aby to zilustrować, zdefiniujmy inną jednostkę reprezentującą blog z wieloma wpisami. W tym przykładzie jednostka jest bez klucza, ale nie musi być.
public class BlogWithMultiplePosts
{
public string Url { get; set; }
public int PostCount { get; set; }
}
Następnie utwórz następującą funkcję o wartości tabeli w bazie danych, która zwraca tylko blogi z wieloma wpisami, a także liczbę wpisów skojarzonych z każdym z tych blogów:
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
)
Teraz jednostkę BlogWithMultiplePosts
można zamapować na tę funkcję w następujący sposób:
modelBuilder.Entity<BlogWithMultiplePosts>().HasNoKey().ToFunction("BlogsWithMultiplePosts");
Uwaga
Aby zamapować jednostkę na funkcję wartości tabeli, funkcja musi być bez parametrów.
Konwencjonalnie właściwości jednostki zostaną zamapowane na pasujące kolumny zwrócone przez tvf. Jeśli kolumny zwracane przez program TVF mają inne nazwy niż właściwość jednostki, kolumny jednostki można skonfigurować przy użyciu HasColumnName
metody, podobnie jak podczas mapowania na zwykłą tabelę.
Gdy typ jednostki jest mapowany na funkcję wartości tabeli, zapytanie:
var query = from b in context.Set<BlogWithMultiplePosts>()
where b.PostCount > 3
select new { b.Url, b.PostCount };
Tworzy następujący kod SQL:
SELECT [b].[Url], [b].[PostCount]
FROM [dbo].[BlogsWithMultiplePosts]() AS [b]
WHERE [b].[PostCount] > 3
Komentarze do tabeli
Możesz ustawić dowolny komentarz tekstowy ustawiony w tabeli bazy danych, co umożliwia dokumentowanie schematu w bazie danych:
[Comment("Blogs managed on the website")]
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
Typy jednostek typu współużytkowanego
Typy jednostek używające tego samego typu CLR są nazywane typami jednostek typu współużytkowanego. Te typy jednostek należy skonfigurować przy użyciu unikatowej nazwy, która musi być podana za każdym razem, gdy używany jest typ jednostki typu współużytkowanego, oprócz typu CLR. Oznacza to, że odpowiednią DbSet
właściwość należy zaimplementować przy użyciu wywołania Set
.
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");
});
}
}