我正在构建一个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);
}
}
答案 0 :(得分:1)
以下是您的方法的优点和缺点:
<强> PRO 强>
CON
话虽这么说,通用回购将更好地满足您的整体需求。以下是它的工作原理:
首先是界面。这很重要,因为它定义了一个共同商定的合同,通过该合同,任何实现它的类都可以保证遵循。
<T>
表示接口被声明为泛型类型。通用类型很甜,因为你可以基本上“模板化”代码并避免重复自己(干!)。 T
是占位符参数,实际类型名称在代码中实际使用时将替代该参数。
where T : class, IEntity, new()
就是一个小笨蛋。通用类型(如此接口)有时需要进行约束 - 通常需要保证任何T
都是引用类型。 :
之后的所有内容都构成了这样的约束集。 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)告诉repos将更改写入数据存储区
在代码中,
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 }
}
答案 1 :(得分:1)
根据我的经验,无论你多么努力,无论你多花多少钱,当你到达项目的最后阶段,并且总是知道你将如何完成它[如果你可以重新开始]。您可以对设计进行大量改进,但需要采取务实的立场。你现在能做什么?
我建议从你拥有的东西开始,以便在你去的时候再次重新启动它......
通用界面非常灵活。我推荐这篇文章。保存并多次阅读; - )
答案 2 :(得分:1)
无论如何,您将在技术上为每个模型拥有一个存储库。每个存储库处理一个模型,并且必须为每个模型实例化。但是,您的第一个示例使用了所谓的“泛型”。它是C#和其他.NET系列语言的一种奇特的,非常强大的功能,它允许您基本上告诉编译器,“我会告诉您我稍后要处理的是什么类型,只是假设我我会给你一个有效的类型“。因此,使用通用存储库,您将只有一个类,但是您将在整个代码中多次实例化它,并传入不同的模型类型:
var catRepository = new Repository<Cat>();
var dogRepository = new Repository<Dog>();
无需定义CatRepository
和DogRepository
等,而无需无限制地使用。