Нужно ли вызывать Dispose для контекста Entity Framework?

258
08 апреля 2022, 16:40

Делаю проект просто с целью обучения, там создал класс CommentService, в котором содержатся методы для работы с БД (с целью сократить код в будущем):

public class CommentService : IDatabaseService<Comment>
{
    private readonly ILogger<CommentService> _logger;
    private readonly DatabaseContext _db;
    public CommentService(ILogger<CommentService> logger, DatabaseContext context)
    {
        _logger = logger;
        _db = context;
    }
    public async void AddEntity(Comment entity)
    {
        _db.Comments.Add(entity);
        await _db.SaveChangesAsync();
    }
    public async Task<List<Comment>> GetAllEntitiesAsync()
    {
        return await _db.Comments.ToListAsync();
    }
    public async Task<List<Comment>> GetAllCommentsByPostId(int postId)
    {
        return await _db.Comments.Where(p => p.PostId == postId).ToListAsync();
    }
    public async Task<Comment> GetEntityByIdAsync(int id)
    {
        return await _db.Comments.FindAsync(id);
    }
    public async void RemoveEntityById(int id)
    {
        _db.Comments.Remove(await GetEntityByIdAsync(id));
        await _db.SaveChangesAsync();
    }
    public void Dispose()
    {
        _db.Dispose();
    }
}

Вопрос состоит в следующем: будет ли правильным такой подход? Имею в виду передачу через конструктор контекста БД из другого класса сюда, а затем вызова Dispose? Или лучше в каждом методе использовать using(DatabaseContext _db = new DatabaseContext())? Как я понимаю, и то, и другое подразумевает Dispose, и он нужен, чтобы можно было работать с контекстом в разных классах и чтобы не было конфликтов, но что более правильно и нужно ли вообще?

Answer 1

Зависит от архитектуры вашего приложения.

В показанном вами варианте ваш CommentService владеет контекстом. Это означает следующее:

  1. контекст не может быть общим для нескольких сервисов;
  2. если вы используете DI - то вам надо регистрировать контекст как Transient.

В то же время, вы можете просто убрать вызов Dispose. В таком случае, ваш CommentService будет заимствовать контекст. Это будет означать следующее:

  1. контекст смогут использовать несколько сервисов одновременно;
  2. тому, кто управляет временем жизни контекста и сервиса, нужно будет следить чтобы контекст не "умер" раньше сервиса;
  3. если вы используете DI - то вам надо регистрировать контекст как Scoped или Singleton.

Вариант с using тоже будет работать, только вам лучше использовать не конструктор, а что-нибудь вроде фабрики контекстов - иначе вы не сможете передать в контекст никаких зависимостей. Вместо фабрики контекстов можно использовать IServiceScopeFactory, но лучше так не делать, поскольку нетипизированная IServiceScopeFactory скрывает тот факт, что сервису нежен именно контекст, а не что-то ещё.

READ ALSO
Правильный вызов данных из коллекции

Правильный вызов данных из коллекции

Объясните мне, а то не врублюсь, как будет быстрее и лучше, и почему:

156
Принцип подстановки Лисков

Принцип подстановки Лисков

Принцип, описывает 3 правила:

171
Как сформировать модель что б обращаться через свойства а не масcивы. С#

Как сформировать модель что б обращаться через свойства а не масcивы. С#

Хочу сформировать модель таким образом что б при возвращение на клиент я обращался через точку и свойство а не через номер в массивеПример

138