我在我的一个应用程序中使用了Entity Framework和Generic Repository。我需要整合工作单元。我对使用Generic Repository Pattern添加工作单元的最佳方法有点困惑,而对应用程序的性能没有任何影响。任何人都可以帮我这样做。
我已添加了我的Generic存储库代码和其他存储库代码,如下所示。
通用存储库:
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);
}
}
答案 0 :(得分:4)
您可能想知道实体框架上下文是工作单元模式的实现(当您context.SaveChanges()
执行工作单元时)。所以我很确定,在90%的情况下,除非你想从具体的DataSource / DataAccess中抽象数据层,否则不需要对它进行额外的实现。我必须说,如果你不需要这个抽象,你根本不需要存储库模式。
无论如何,这个问题太宽泛了。您应该在应用程序中描述您想要使用存储库模式的意图。
答案 1 :(得分:1)
有使用通用存储库的专家和骗局。在其界面中具有IQueryable的存储库可以说明了底层技术,这意味着替换这种底层技术变得更加困难,因为IQueryable并不那么容易实现。因此,有人说通用存储库不提供任何抽象,你也可以在没有通用存储库的情况下立即使用EF。 (如果你不能用不同的实现替换一个层,那么你与该实现的关系太紧了)。您会发现也有人赞成使用通用存储库。存储库可以具有可模拟的接口和接口,并且您的代码将易于单元测试。使用或不使用通用存储库是基于大部分意见。因为你使用的是我认为你有充分的理由需要一个
但我认为你不应该从头开始编写自己的通用存储库/ unitofwork。最好基于一些已经免费提供的实现并提供良好的功能,例如这个:
https://genericunitofworkandrepositories.codeplex.com/
它提供您所需要的功能,并提供强大的查询功能,并支持async和await。
工作单元本身并不是对性能的威胁,因为它只是EF环境的包装,实际上它已经是一个工作单元。性能问题位于您执行的查询中。那些需要逐一评估。还有很多事情需要考虑。
- lazy loading
- eager loading
- explicit loading
您可能希望阅读我对使用EF过度使用包含的问题的回答:
Optimize Entity framework Query, avoid lazy-loading。
表演是一个很大的话题。没有简单的答案,肯定没有一个答案适合所有EF性能问题。