是否有推荐的基础存储库类与Entity Framework一起使用?

时间:2012-07-11 15:55:51

标签: asp.net-mvc-3 entity-framework dependency-injection ef-code-first entity-framework-4.3

我正在使用一个带有ASP.NET MVC 3应用程序的EF Code First方法,而不是重新创建轮子,我想知道是否已存在我的自定义Repository类可以扩展的可靠的基础Repository类为了提供开箱即用的默认功能(例如基本的CRUD等)。

所以这样......

public class CustomerRepository : BaseRepository { ... }
因此,

...将提供一种默认方式来处理开箱即用的Customer对象。我想在我的MVC控制器中注入一个ICustomerRepository,并在那里为我提供这些功能。

我确信这样的东西已经存在,因为我已经用NHibernate做了类似的事情。

由于

4 个答案:

答案 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添加通用存储库中获益。