0

我正在构建一个 MVC 4 网站,并且正在尝试遵循存储库模式。

我见过一个复杂的设置,如下所示,但由于我的技能水平,我无法完成:

public interface IEntityRepository<T>
    where T : class, IEntity, new()
{
    void CommitChanges();
    void DeleteOnCommit(T entity);
    T GetEntity(int key);
    IQueryable<T> GetAll();
    int InsertOnCommit(T entity);
}

由于简单,我选择了这种方法:

public class EntityAdminRepository : IAdminRepository {

    AdminEntities db = new AdminEntities();

    public Models.Product CreateNewProduct(Models.Product productToCreate) {
       db.Products.Add(productToCreate);
       return productToCreate;
    }

    public void DeleteProduct(int id) {
        db.Products.Remove(GetProductByID(id));
    }

    public Models.Product GetProductByID(int id) {
        return db.Products.FirstOrDefault(d => d.ID == id);
    }

    public IEnumerable<Models.Product> GetAllProducts() {
        return db.Products;
    }

    public Models.Category CreateNewCategory(Models.Category categoryToCreate) {
        throw new NotImplementedException();
    }

    public void DeleteCategory(int id) {
        throw new NotImplementedException();
    }

    public Models.Category GetCategoryByID(int id) {
        throw new NotImplementedException();
    }

    public IEnumerable<Models.Category> GetAllCategories() {
        throw new NotImplementedException();
    }

    public int SaveChanges() {
       return db.SaveChanges();
    }
}

除了扩大规模的问题(我认为无论如何都会存在于其他地方)这个解决方案是否如此可怕,我应该立即放弃它并继续努力,直到我能够理解并实施最初的例子?

更新 1: 我使用第一种方法的问题是我不知道如何在控制器中重新创建以下功能:

    protected IAdminRepository _repository;

    public AdminController() : this(new EntityAdminRepository()) { }
    public AdminController(IAdminRepository repository) {
        _repository = repository;
    }

这种方式意味着我对每个 DTO 都有一个实体,这一切如何共同达到高潮?

更新 2:

public class DatabaseRepository<T> : IRepository<T> 
    : where T:class, IEntity, new() 
{
    private DbContext context = new MyDbContext(); // proper data actions
    public T GetEntity(int id) 
    {
        return context.Tables<T>.FirstOrDefault(x => x.Id == id);
    }
}

public class InMemoryRepository<T> : IRepository<T> 
    : where T:class, IEntity, new() 
{
    private List<T> context = new List<T>(); // stuff for unit testing
    public T GetEntity(int id) 
    {
        return context.FirstOrDefault(x => x.Id == id);
    }
}
4

3 回答 3

1

以下是您的方法的一些优点和缺点:

专业版

  • 简单的
  • 容易明白
  • 显式
  • 做你需要的
  • 直接测试

CON

  • 大量模型类型时笨拙
  • 大量重复代码
  • 不利用继承或泛型之类的东西
  • 添加新功能本质上是有风险的,因为需要单独对每个存储库进行更改

话虽如此,通用存储库总体上更能满足您的需求。以下是它的工作原理:

首先,界面。这很重要,因为它定义了一个共同商定的契约,任何实现它的类都保证遵循该契约。

<T>意味着接口被声明为泛型类型。泛型类型很不错,因为您基本上可以“模板化”您的代码并避免重复自己(干!)。这T是一个占位符参数,实际类型名称将代替它在代码中实际使用的时间。

where T : class, IEntity, new()如果您不熟悉它,它会有点麻烦。像这个接口这样的泛型类型有时需要受到约束——例如,您通常需要保证 anyT是引用类型。之后的一切都:构成了这样一个约束集。class意味着任何值都T必须是类,而不是值类型。IEntity意味着任何类T都必须执行IEntity合同。new()是最不直观的,意味着T必须有一个默认的、无参数的构造函数。那很重要,因为您经常希望能够简单地调用var a = new T().

这是一个例子

public interface IEntity { public int Id { get; set;} }

public class FooEntity : IEntity { public int Id { get; set; } }

public class Repository<T> : IRepository<T> 
    : where T:class, IEntity, new() 
{
    private DbContext context = new MyDbContext(); // or however your db store works

    public Repository(IDbContext ctx) { context = ctx; }

    public T GetEntity(int id) 
    {
        return context.Tables<T>.FirstOrDefault(x => x.Id == id);
    }
}

请注意我仍在使用这些<T>东西吗?这就是特制酱汁。这意味着我可以这样使用我ProductRepository的:

var a = new Repository<Product>();
var foo = a.GetByKey(1234); //foo is Product

现在,要使用 repo 处理和修改对象,您有一条直截了当的路径:

1) 从存储库中获取要更改的对象 2) 对对象进行更改 3) 告诉存储库将更改写入数据存储

在代码中,

var a = new Repository<Product>(/* optionally, a mocked context object */);
var foo = a.GetByKey(1234); //foo is Product
// modify
foo.Name = "Bleach";
a.CommitChanges();
// create
var bar = new Product();
bar.Name = "Paper Towels";
a.InsertOnSubmit(bar);
a.CommitChanges();

这是一个 MVC 示例,假设您更新帖子中的控制器示例:

// ctor not listed here

public ActionResult AddProduct(Product product)
{
    if (Model.IsValid) // validate the model - may not be exact syntax...
    {
        _repository.InsertOnSubmit(product);
        _repository.CommitChanges();

        return View(product);
    }
    else { //do something else }
}
于 2013-03-07T19:24:48.667 回答
1

以我的经验,无论你多么努力,花费多长时间,当你完成一个项目并且总是知道你会如何完成它(如果你可以重新开始的话)。您可以对设计进行大量改进,但您需要采取务实的立场。你现在能做什么?

我建议从你所拥有的开始,以便在你去的时候再次重新启动它几次......


通用接口非常灵活。我推荐这篇文章。保存并多次阅读;-)

.NET Junkie - 查询/命令

于 2013-03-07T19:27:59.520 回答
1

无论如何,从技术上讲,每个模型都有一个存储库。每个存储库处理一个模型,并且必须为每个模型实例化。但是,您的第一个示例使用了所谓的“泛型”。这是 C# 和其他 .NET 家族语言的一个奇特且非常强大的功能,它允许您从本质上告诉编译器,“我稍后会告诉你我在这里处理的是什么类型,假设我要喂你一个有效类型”。因此,使用通用存储库,您将只有一个类,但您将在整个代码中使用传入的不同模型类型多次实例化它:

var catRepository = new Repository<Cat>();
var dogRepository = new Repository<Dog>();

不必定义 aCatRepository和 aDogRepository等等,无穷无尽。

于 2013-03-07T19:29:23.923 回答