Определение моделей

Последнее обновление: 18.11.2021

Включение сущностей в модель

По умолчанию все типы сущностей, для которых определены в контексте данных наборы DbSet, включаются в модель и в дальнейшем сопоставляются с таблицами в базе данных. Например:

using Microsoft.EntityFrameworkCore;

public class ApplicationContext : DbContext
{
    public DbSet<User> Users { get; set; } = null!;
    public ApplicationContext()
    {
        Database.EnsureDeleted();
        Database.EnsureCreated();
    }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite("Data Source=helloapp.db");
    }
}
public class User
{
    public int Id { get; set; }
    public string? Name { get; set; }
    public int Age { get; set; }
}

В данном случае, поскольку для класса User в классе контекста определено свойство типа DbSet

public DbSet<User> Users { get; set; } = null!;

Таким образом, для сущности User будет создана таблица в бд.

Ссылочные nullable-типы и DbSet

Класс DbSet, как и другие типы, является ссылочным. А, начиная с C# 10 и .NET 6 автоматически применяется функциональность ссылочных nullable-типов. И переменные/свойства тех типов, которые не являются nullable, следует инициализировать некотором значением перед их использованием. Например, если мы напишем:

public DbSet<User> Users { get; set; }

То мы столкнемся с предупреждением:

Nullable и DbSet в Entity Framework Core

То есть нам надо инициализировать свойство типа DbSet. Хотя в этом нет большого смысла, так как контструктор базового класса DbContext гарантирует, что все свойства типа DbSet будут инициализированы и соответственно в принципе не будут иметь значение null.

Тем не менее проблема остается, поскольку мы сталкиваемся с предупреждением. Чтобы выйти из этой ситуации мы можем инициализировать свойство с помощью выражения null!, которое говорит, что данное свойство в принципе не будет иметь значение null:

public DbSet<User> Users { get; set; } = null!;

Другое решение - инициализировать свойство значением типа Set<T>:

public DbSet<User> Users => Set<User>();

Включение сущностей в модель без DbSet

Но кроме того, в модель также включаются типы, на которые есть ссылки в сущностях, которые уже включены в модель, например, через свойства DbSet.

Например, пусть у нас определены следующие сущности:

public class User
{
    public int Id { get; set; }
    public string? Name { get; set; }
    public int Age { get; set; }
    // навигационное свойство
    public Company? Company { get; set; }
}

public class Company
{
    public int Id { get; set; }
    public string? Name { get; set; }
}
public class Country
{
    public int Id { get; set; }
    public string? Name { get; set; }
}

И пусть у нас будет класс контекста данных:

using Microsoft.EntityFrameworkCore;

public class ApplicationContext : DbContext
{
    public DbSet<User> Users { get; set; } = null!;
    public ApplicationContext()
    {
        Database.EnsureDeleted();
        Database.EnsureCreated();
    }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite("Data Source=helloapp.db");
    }
}

После создания базы данных в ней будут созданы две таблицы: Users и Company. А третий класс - Country никак не используется в сущностях User и Company, для Country нет свойства DbSet в классе контекста, поэтому она не будет включена в контекст и для нее не будет создаваться таблица в бд.

Навигационное свойство в Entity Framework Core и C#

Поскольку для типа User определен набор DbSet, то для имени таблицы будет применяться имя этого набора, а для второй таблицы будет использоваться имя класса Company.

Еще один способ включения сущности в модель представляет вызов Entity() объекта ModelBuilder в методе OnModelCreating():

using Microsoft.EntityFrameworkCore;

public class ApplicationContext : DbContext
{
    public DbSet<User> Users { get; set; } = null!;
    public ApplicationContext()
    {
        Database.EnsureDeleted();
        Database.EnsureCreated();
    }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite("Data Source=helloapp.db");
    }
	protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Country>();
    }
}

И если мы сейчас создадим и выполним миграции, то в базе данных будут уже три таблицы для сущностей:

Fluent API в Entity Framework Core и C#

Исключение из модели

Иногда возникают ситуации, когда надо, наоборот, исключить сущность из модели. Например, в примере выше сущность Company ссылается на класс Company, и, допустим, мы не хотим, чтобы в базе данных была таблица Company. В этом случае мы можем использовать Fluent API или аннотации данных.

Применение Fluent API заключается в вызове метода Ignore():

using Microsoft.EntityFrameworkCore;

public class ApplicationContext : DbContext
{
    public DbSet<User> Users { get; set; } = null!;
    public ApplicationContext()
    {
        Database.EnsureDeleted();
        Database.EnsureCreated();
    }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite("Data Source=helloapp.db");
    }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Ignore<Company>();
    }
}

Аннотации данных предполагают установку над классом атрибута [NotMapped]:

using System.ComponentModel.DataAnnotations.Schema;

public class User
{
    public int Id { get; set; }
    public string? Name { get; set; }
    public int Age { get; set; }
    // навигационное свойство
    public Company? Company { get; set; }
}
[NotMapped]
public class Company
{
    public int Id { get; set; }
    public string Name { get; set; }
}

При исключении сущности Company в базе данных будет только одна таблица Users, причем она не будет содержать столбца, который бы сопоставлялся со свойством Company класса User:

Исключение сущностей из модели и Ignore и NotMapped в Entity Framework Core
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850