Типы сущностей
Включение dbSet типа в контекст означает, что он включен в модель EF Core; Обычно мы называем такой тип сущностью. EF Core может считывать и записывать экземпляры сущностей из базы данных или в базу данных, а если используется реляционная база данных, EF Core может создавать таблицы для сущностей с помощью миграций.
Включение типов в модель
По соглашению типы, предоставляемые в свойствах DbSet в контексте, включаются в модель как сущности. Типы сущностей, указанные в OnModelCreating
методе, также включаются, как и любые типы, найденные путем рекурсивного изучения свойств навигации других обнаруженных типов сущностей.
В приведенном ниже примере кода включены все типы:
Blog
включается, так как он предоставляется в свойстве DbSet в контексте.Post
включается, так как он обнаружен с помощьюBlog.Posts
свойства навигации.AuditEntry
поскольку он указан в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; }
}
Исключение типов из модели
Если вы не хотите, чтобы тип был включен в модель, его можно исключить:
[NotMapped]
public class BlogMetadata
{
public DateTime LoadedFromDatabase { get; set; }
}
Исключение из миграций
Иногда полезно иметь один и тот же тип сущности, сопоставленный в нескольких DbContext
типах. Это особенно верно при использовании ограничивающих контекстов, для которых обычно используется другой DbContext
тип для каждого ограниченного контекста.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<IdentityUser>()
.ToTable("AspNetUsers", t => t.ExcludeFromMigrations());
}
При миграции конфигурации таблица не будет создана AspNetUsers
, но IdentityUser
она все еще включена в модель и может использоваться обычно.
Если вам нужно снова начать управление таблицей с помощью миграций, необходимо создать новую миграцию, где AspNetUsers
не исключается. Следующая миграция теперь будет содержать любые изменения, внесенные в таблицу.
Имя таблицы
По соглашению каждый тип сущности будет настроен для сопоставления с таблицей базы данных с тем же именем, что и свойство DbSet, которое предоставляет сущность. Если для данной сущности нет dbSet, используется имя класса.
Вы можете вручную настроить имя таблицы:
[Table("blogs")]
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
Схема таблицы
При использовании реляционной базы данных таблицы создаются по соглашению в схеме по умолчанию базы данных. Например, Microsoft SQL Server будет использовать схему dbo
(SQLite не поддерживает схемы).
Таблицы можно настроить для создания в определенной схеме следующим образом:
[Table("blogs", Schema = "blogging")]
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
Вместо указания схемы для каждой таблицы можно также определить схему по умолчанию на уровне модели с помощью API fluent:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("blogging");
}
Обратите внимание, что настройка схемы по умолчанию также влияет на другие объекты базы данных, такие как последовательности.
Сопоставление представлений
Типы сущностей можно сопоставить с представлениями базы данных с помощью API Fluent.
Примечание.
EF предполагает, что указанное представление уже существует в базе данных, оно не создаст его автоматически в миграции.
modelBuilder.Entity<Blog>()
.ToView("blogsView", schema: "blogging");
Сопоставление с представлением приведет к удалению сопоставления таблиц по умолчанию, но тип сущности также можно сопоставить с таблицей явным образом. В этом случае сопоставление запросов будет использоваться для запросов, а сопоставление таблиц будет использоваться для обновлений.
Совет
Чтобы протестировать типы сущностей без ключа, сопоставленные с представлениями с помощью поставщика в памяти, сопоставите их с запросом через ToInMemoryQuery. Дополнительные сведения см. в документации поставщика в памяти.
Сопоставление функций с табличным значением
Можно сопоставить тип сущности с табличной функцией (TVF) вместо таблицы в базе данных. Чтобы проиллюстрировать это, давайте определим другую сущность, представляющую блог с несколькими записями. В примере сущность является бессерверной, но она не должна быть.
public class BlogWithMultiplePosts
{
public string Url { get; set; }
public int PostCount { get; set; }
}
Затем создайте в базе данных следующую табличное значение функцию, которая возвращает только блоги с несколькими записями, а также количество записей, связанных с каждым из этих блогов:
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
)
Теперь сущность BlogWithMultiplePosts
можно сопоставить с этой функцией следующим образом:
modelBuilder.Entity<BlogWithMultiplePosts>().HasNoKey().ToFunction("BlogsWithMultiplePosts");
Примечание.
Чтобы сопоставить сущность с табличным значением функции, функция должна быть без параметров.
Обычно свойства сущности сопоставляются с соответствующими столбцами, возвращаемыми TVF. Если столбцы, возвращаемые TVF, имеют разные имена, отличные от свойства сущности, столбцы сущности можно настроить с помощью HasColumnName
метода, как при сопоставлении с обычной таблицей.
Если тип сущности сопоставляется с табличным значением функции, запрос:
var query = from b in context.Set<BlogWithMultiplePosts>()
where b.PostCount > 3
select new { b.Url, b.PostCount };
Преобразуется в следующий запрос SQL:
SELECT [b].[Url], [b].[PostCount]
FROM [dbo].[BlogsWithMultiplePosts]() AS [b]
WHERE [b].[PostCount] > 3
Примечания к таблицам
Можно задать произвольный текстовый комментарий, который устанавливается в таблице базы данных, что позволяет документировать схему в базе данных:
[Comment("Blogs managed on the website")]
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
Типы сущностей общего типа
Типы сущностей, использующие тот же тип СРЕДЫ CLR, называются типами сущностей общего типа. Эти типы сущностей должны быть настроены с уникальным именем, которое должно быть предоставлено при использовании типа сущности общего типа в дополнение к типу СРЕДЫ CLR. Это означает, что соответствующее DbSet
свойство должно быть реализовано 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");
});
}
}