Типы сущностей
Включение 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:
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");
});
}
}