我正在使用一个带有ASP.NET MVC 3应用程序的EF Code First方法,而不是重新创建轮子,我想知道是否已存在我的自定义Repository类可以扩展的可靠的基础Repository类为了提供开箱即用的默认功能(例如基本的CRUD等)。
所以这样......
public class CustomerRepository : BaseRepository { ... }
因此,...将提供一种默认方式来处理开箱即用的Customer对象。我想在我的MVC控制器中注入一个ICustomerRepository,并在那里为我提供这些功能。
我确信这样的东西已经存在,因为我已经用NHibernate做了类似的事情。
由于
答案 0 :(得分:5)
不,没有内置存储库,除了EF本身(其本身就是工作单元模式的实现,而DbSet基本上是存储库)。
目前,软件界对于通用存储库是否具有很大的实际价值存在争议。出于测试目的,许多人认为,它们提供了简单的单元测试。其他人说单元测试存储库没有帮助,因为模拟存储库的行为与实际存储库的行为不同(因为linq - > Sql转换层,在模拟的存储库中不存在)。
许多人建议您使用内存数据库(如SqlLite)对EF进行集成测试,而不是对其进行单元测试。
尽管如此,如果您打算使用存储库,网上有很多示例,具有不同的样式和方法。或者你可以自己动手。 MS没有提供。
答案 1 :(得分:3)
根据我的经验,编写自己的存储库是多余的,因为EF已经通过DbSet实现了这种模式。
我在最近的一个项目中使用MVC3 + EF Code Fisrt。我们在一些教程之后开始实现通用存储库,很快我们意识到我们正在编写大量不必要的冗余代码。实际上,存储库只给我们提供了很多DbSet的功能。最后,我们决定删除它们并直接使用我们的DbContext和DbSet。
但是,除了简单的CRUD操作之外,复杂的业务逻辑如何?
好吧,我们通过服务层公开了查询和多个CRUD操作等所有复杂功能。您可以按功能构建不同的服务类。例如,您可以编写AccountService来管理与用户帐户相关的所有功能。像这样:
public class AccountService {
private MyContext ctx;
public AccountService(DbContext dbContext) {
this.ctx = (MyContext)dbContext;
}
/// <summary>
/// Gets the underlying DbContext object.
/// </summary>
public DbContext DbContext {
get { return ctx; }
}
/// <summary>
/// Gets the users repository.
/// </summary>
public DbSet<User> Users {
get {return ctx.Users;}
}
public bool ValidateLogin(string username, string password) {
return ctx.Users.Any(u => u.Username == username && u.Password == password);
}
public string[] GetRolesForUser(string username) {
var qry = from u in ctx.Users
from r in u.Roles
where u.Username == username
select r.Code;
return qry.ToArray<String>();
}
public User CreateUser(string username, string password) {
if (String.IsNullOrWhiteSpace(username)) throw new ArgumentException("Invalid user name");
if (String.IsNullOrWhiteSpace(password)) throw new ArgumentException("Invalid password");
User u = new User {
Username = username.Trim().ToLower(),
Password = password.Trim().ToLower(),
Roles = new List<Role>()
};
ctx.Users.Add(u);
ctx.SaveChanges();
return u;
}
依赖注入怎么样?
使用这种方法,我们唯一需要注入的是DbContext。服务类有一个带有DbContext的构造函数。因此,当您的控制器构造函数接受服务实例时,将向其注入DbContext。
编辑:示例代码
这是一个关于控制器外观的示例代码:
public class HomeController : Controller {
private readonly AccountService accountService;
public AccountController(AccountService accountService) {
this.accountService = accountService;
}
}
这可能是使用NInject的DI配置:
private static void RegisterServices(IKernel kernel) {
kernel.Bind<MyContext>().ToSelf().InRequestScope();
kernel.Bind<DbContext>().ToMethod(ctx => ctx.Kernel.Get<MyContext>());
}
单元测试怎么样?
您可以为每个服务层类构建特定的接口,并在需要的地方进行模拟。
答案 2 :(得分:0)
我的一位朋友,萨莎巴伯写了一篇很好的文章,内容涉及其中一些想法。
链接可以在这里找到。
RESTful WCF / EF POCO / Unit of Work / Repository / MEF: 1 of 2
答案 3 :(得分:0)
EF有一个名为DbContext
的基类。您可以添加DbSet<TEntity>
这允许你做这样的事情:
public class User {
public int Id { get; set; }
public string Name { get; set; }
}
public class DatabaseContext : DbContext {
public DbSet<User> Users { get; set; }
}
您现在可以这样使用:
using(var db = new DatabaseContext()) {
User jon = new User {Name = "Jon Smith"};
db.Users.Add(jon);
db.SaveChanges();
var jonById = db.Users.Single(x => x.Id == 1);
}
如果你想要更多抽象,请参阅这篇关于围绕EF Entity Framework 4 CTP 4 / CTP 5 Generic Repository Pattern and Unit Testable构建通用存储库的帖子。请注意,并不总是需要这种抽象级别。您应该决定是否真正从直接使用DbContext添加通用存储库中获益。