Entity Framework с общим репозиторием и единицей работы

Я использую Entity Framework с универсальным репозиторием в одном из моих приложений. Мне нужно интегрировать единицу работы. Меня немного смущает, что это лучший способ добавить единицу работы с Generic Repository Pattern без какого-либо влияния на производительность приложения. Может ли кто-нибудь помочь мне сделать это.

Я добавил мой общий код репозитория и другой код репозитория, как показано ниже.

Общий репозиторий:

using System;
using System.Data.Entity;
using System.Data.Entity.Validation;
using System.Linq;
using System.Threading.Tasks;
using EntityFrameworkDemo.Entity;
using EntityFrameworkDemo.Models;
using EntityFrameworkDemo.Repository.UnitOfWork;

namespace EntityFrameworkDemo.Repository
{
    public class BaseRepository<T> : IDisposable where T : BaseModel
    {
      internal EFContext db;

    public BaseRepository()
    {
        db = new EFContext();
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="BaseRepository"/> class.
    /// </summary>
    /// <param name="context">The context.</param>
    public BaseRepository(EFContext context)
    {
        db = context;
    }

    /// <summary>
    /// Gets this instance.
    /// </summary>
    /// <returns></returns>
    public IQueryable<T> GetAll()
    {
        return db.Set<T>().Where(t => !t.DeletedOn.HasValue);
    }



    /// <summary>
    /// Gets the specified identifier.
    /// </summary>
    /// <param name="id">The identifier.</param>
    /// <returns></returns>
    public T Get(long? id)
    {
        return db.Set<T>().Find(id); ;
    }

    /// <summary>
    /// Gets the specified identifier.
    /// </summary>
    /// <param name="id">The identifier.</param>
    /// <returns></returns>
    public Task<T> GetASync(long? id)
    {
        return db.Set<T>().FindAsync(id);
    }

    /// <summary>
    /// Inserts the specified current.
    /// </summary>
    /// <param name="current">The current.</param>
    /// <returns></returns>
    public async Task<T> Insert(T current)
    {
        db.Set<T>().Add(current);

        try
        {
            await db.SaveChangesAsync();
        }
        catch (DbEntityValidationException e)
        {
            foreach (var eve in e.EntityValidationErrors)
            {
                Console.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
                    eve.Entry.Entity.GetType().Name, eve.Entry.State);
                foreach (var ve in eve.ValidationErrors)
                {
                    Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
                        ve.PropertyName, ve.ErrorMessage);
                }
            }
            throw;
        }

        return await db.Set<T>().FirstAsync();
    }

    /// <summary>
    /// Inserts the specified current.
    /// </summary>
    /// <param name="current">The current.</param>
    /// <returns></returns>
    public async Task Update(T current)
    {
        db.Entry<T>(current).State = System.Data.Entity.EntityState.Modified;

        try
        {
            await db.SaveChangesAsync();
        }
        catch (DbEntityValidationException e)
        {
            foreach (var eve in e.EntityValidationErrors)
            {
                Console.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the f  ollowing validation errors:",
                    eve.Entry.Entity.GetType().Name, eve.Entry.State);
                foreach (var ve in eve.ValidationErrors)
                {
                    Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
                        ve.PropertyName, ve.ErrorMessage);
                }
            }
            throw;
        }

    }

    /// <summary>
    /// Deletes the specified identifier.
    /// </summary>
    /// <param name="id">The identifier.</param>
    /// <returns></returns>
    public async Task Delete(long? id)
    {
        var current = await this.GetASync(id);
        if (current != null)
        {
            current.DeletedOn = DateTime.Now;
            db.Entry<T>(current).State = System.Data.Entity.EntityState.Modified;
            await db.SaveChangesAsync();
        }
    }

    /// <summary>
    /// Deletes the specified identifier permanently.
    /// </summary>
    /// <param name="id">The identifier.</param>
    /// <returns></returns>
    public async Task DeletePermanently(long? id)
    {
        var current = await this.GetASync(id);
        if (current != null)
        {
            db.Set<T>().Remove(current);
            await db.SaveChangesAsync();
        }
    }

    /// <summary>
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
    /// </summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// Finalizes an instance of the <see cref="BaseRepository"/> class.
    /// </summary>
    ~BaseRepository()
    {
        Dispose(false);
    }

    /// <summary>
    /// Releases unmanaged and - optionally - managed resources.
    /// </summary>
    /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (db != null)
            {
                db.Dispose();
                db = null;
            }
        }
    }
}

}

Студенческое хранилище:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EntityFrameworkDemo.Models;

namespace EntityFrameworkDemo.Repository
{
    public class StudentRepository : BaseRepository<Student>
    {
    public StudentRepository()
        : base()
    { }

    }
}

контроллер:

 public class HomeController : Controller
{
    private StudentRepository studentRepo = new StudentRepository();

    public async Task<ActionResult> Index()
    {
        var test = studentRepo.GetAll();

        return View();
    }
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            studentRepo.Dispose();
        }
        base.Dispose(disposing);
    }
}

2 ответа

Возможно, вы захотите узнать, что контекст Entity Framework является реализацией шаблона единицы работы (когда вы context.SaveChanges() Вы выполняете единицу работы). Так что я уверен, что в 90% случаев нет необходимости делать дополнительную реализацию над ним, если только вы не хотите абстрагировать свой слой данных от конкретного DataSource/DataAccess. Я должен сказать, что если вам не нужна эта абстракция, вам вообще не нужен шаблон хранилища.

В любом случае, вопрос слишком широк. Вы должны описать свои намерения по поводу того, почему вы хотите использовать шаблон репозитория в своем приложении.

Есть за и против использования универсального репозитория. Репозиторий, имеющий IQueryable в своем интерфейсе, вероятно, показывает основную технологию, а это означает, что заменить эту базовую технологию становится намного сложнее, поскольку IQueryable не так легко реализовать. Следовательно, есть люди, которые говорят, что универсальный репозиторий не предоставляет какой-либо абстракции, и вы также можете сразу использовать EF без универсального репозитория. (Если вы не можете заменить слой другой реализацией, вы слишком тесно связаны с этой реализацией). Вы также обнаружите, что есть люди, которые выступают за использование общего хранилища. У репозиториев могут быть интерфейсы, а интерфейсы можно смоделировать, и ваш код будет легко тестировать. Использовать или не использовать общий репозиторий в значительной степени основано на мнении. Поскольку вы используете один, я полагаю, у вас есть веская причина для его

Но я не думаю, что вы должны писать свои собственные общие репозитории /unitofwork с нуля. Лучше опираться на некоторые реализации, которые уже находятся в свободном доступе и предлагают хорошую функциональность, например, такую:

https://genericunitofworkandrepositories.codeplex.com/

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

Сама единица работы не является угрозой для производительности, потому что это просто оболочка вокруг контекста EF, которая на самом деле уже является единицей работы. Проблемы с производительностью находятся в запросах, которые вы выполняете. Те должны быть оценены один за другим. И есть много вещей, чтобы рассмотреть.

- lazy loading
- eager loading
- explicit loading

Возможно, вы захотите прочитать мой ответ на этот вопрос о чрезмерном использовании включений с использованием EF:

Оптимизируйте Entity Framework Query, избегайте отложенной загрузки.

Производительность - большая тема. Нет простого ответа, и определенно нет единственного ответа, который отвечал бы всем проблемам производительности EF.

Другие вопросы по тегам