Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 数据库抽象层设计-正确使用IRepository?_.net_Asp.net Mvc_Database Abstraction - Fatal编程技术网

.net 数据库抽象层设计-正确使用IRepository?

.net 数据库抽象层设计-正确使用IRepository?,.net,asp.net-mvc,database-abstraction,.net,Asp.net Mvc,Database Abstraction,我正在设计我的ASP.NETMVC应用程序,我遇到了一些有趣的想法 我看到的许多示例都描述并使用了存储库模式(IRepository),所以我在学习MVC时就是这样做的 现在我知道这一切都在做什么,我开始审视我目前的设计,想知道这是否是最好的方式 目前我有一个基本的IUserRepository,它定义了一些方法,如FindById(),SaveChanges(),等等 目前,每当我想在数据库中加载/查询用户表时,我都会按照以下步骤进行操作: private IUserRepositor

我正在设计我的ASP.NETMVC应用程序,我遇到了一些有趣的想法

我看到的许多示例都描述并使用了存储库模式(
IRepository
),所以我在学习MVC时就是这样做的

现在我知道这一切都在做什么,我开始审视我目前的设计,想知道这是否是最好的方式

目前我有一个基本的
IUserRepository
,它定义了一些方法,如
FindById()
SaveChanges()
,等等

目前,每当我想在数据库中加载/查询用户表时,我都会按照以下步骤进行操作:

    private IUserRepository Repository;

    public UserController()
        : this(new UserRepository())
    { }

    [RequiresAuthentication]
    [AcceptVerbs(HttpVerbs.Get)]
    public ActionResult Edit(string ReturnUrl, string FirstRun)
    {
        var user = Repository.FindById(User.Identity.Name);

        var viewModel = Mapper.Map<User, UserEditViewModel>(user);
        viewModel.FirstRun = FirstRun == "1" ? true : false;

        return View("Edit", viewModel);
    }

    [AcceptVerbs(HttpVerbs.Post), ValidateAntiForgeryToken(Salt = "SaltAndPepper")]
    public ActionResult Edit(UserEditViewModel viewModel, string ReturnUrl)
    {
        //Map the ViewModel to the Model
        var user = Repository.FindById(User.Identity.Name);

        //Map changes to the user
        Mapper.Map<UserEditViewModel, User>(viewModel, user);

        //Save the DB changes
        Repository.SaveChanges();

        if (!string.IsNullOrEmpty(ReturnUrl))
            return Redirect(ReturnUrl);
        else
            return RedirectToAction("Index", "User");
    }
私有IUSER存储库;
公共用户控制器()
:此(新用户存储库())
{ }
[需要重新验证]
[接受动词(HttpVerbs.Get)]
公共操作结果编辑(字符串返回URL,字符串首次运行)
{
var user=Repository.FindById(user.Identity.Name);
var viewModel=Mapper.Map(用户);
viewModel.FirstRun=FirstRun==“1”?真:假;
返回视图(“编辑”,视图模型);
}
[AcceptVerbs(HttpVerbs.Post),ValidateAntiForgeryToken(Salt=“SaltAndPepper”)]
公共操作结果编辑(UserEditViewModel viewModel,字符串返回URL)
{
//将ViewModel映射到模型
var user=Repository.FindById(user.Identity.Name);
//将更改映射到用户
Mapper.Map(视图模型,用户);
//保存数据库更改
SaveChanges();
如果(!string.IsNullOrEmpty(ReturnUrl))
返回重定向(ReturnUrl);
其他的
返回重定向操作(“索引”、“用户”);
}
现在,我不完全理解MVC在用户创建链接时如何创建控制器(不确定每个用户是否有一个控制器或每个应用程序是否有一个控制器),因此我不确定最佳做法

我发现了一个关于使用通用存储库接口
IRepository
的大问题,而且在许多博客上似乎也提出了静态
RepositoryFactory
的想法。基本上只保存了一个存储库实例,它是通过这个工厂获得的

所以我的问题围绕着人们在这些应用程序中是如何做到这一点的,以及什么是好的实践

人们是否有基于每个表的单独存储库(
IUserRepository
)?
他们是否使用通用的
i假设?
他们是否使用静态存储库工厂?
或者完全是别的什么

编辑: 我刚刚意识到我也应该问:

在每个控制器上安装一个私有的
i存储系统是一个好方法吗?或者每次我想使用一个新的
IRepository

赏金编辑: 我开始悬赏以获得更多的观点(并不是说蒂姆的观点没有帮助)

我更想知道人们在MVC应用程序中做了什么,或者他们认为什么是好主意。

人们是否有基于每个表的单独存储库(IUserRepository)? 我倾向于每个聚合都有一个存储库,而不是每个表

他们是否使用通用的IRepository? 如果可能,可以

他们是否使用静态存储库工厂?
我更喜欢通过IOC容器注入存储库实例

以下是我如何使用它。我将IRepository用于我的所有存储库所共有的所有操作

public interface IRepository<T> where T : PersistentObject
{
    T GetById(object id);
    T[] GetAll();
    void Save(T entity);
}
然后使用自定义控制器工厂使用依赖项注入模式实例化存储库。我正在使用作为依赖项注入层

数据库层是NHibernate。ISession是此会话中数据库的网关

我建议你看看结构,你可以从中学到很多东西

你可以从中学习的另一个项目是。我还没有充分挖掘。

人们是否有基于每个表的单独存储库(IUserRepository)?

是的,这是一个更好的选择,原因有二:

  • 我的DAL基于Linq to Sql(但我的DTO是基于LTS实体的接口)
  • 执行的操作是原子操作(添加是一个原子操作,保存是另一个原子操作,等等)
他们是否使用通用IRepository?

是的,独家,受DDD实体/价值方案的启发,我创建了IRepositoryEntity/IRepositoryValue,并为其他内容创建了通用IRepository

他们是否使用静态存储库工厂?

是和否:我使用通过静态类调用的IOC容器。 好。。。我们可以说这是一种工厂


注意:我自己设计了这个架构,我的一位同事发现它非常棒,我们目前正在基于这个模型创建整个公司框架(是的,这是一家年轻的公司)。这绝对值得一试,即使我觉得主要参与者将发布这种框架。

通用
I假设的想法存在一些非常明显的问题:

  • 它假设每个实体使用相同类型的密钥,这在几乎任何非平凡的系统中都是不正确的。一些实体将使用guid,其他实体可能具有某种自然键和/或复合键。NHibernate可以很好地支持这一点,但是LINQtoSQL在这方面非常糟糕——您必须编写大量的黑客代码来进行自动密钥映射

  • 这意味着每个存储库只能处理一种实体类型,并且只支持最简单的操作。当一个存储库被降级为这样一个简单的CRUD包装器时,它几乎没有什么用处。您也可以将
    IQueryable
    交给客户机

  • 它假定您对每个实体执行完全相同的操作。事实上,这将是非常遥远的
    public interface IUserRepository : IRepository<User>
    {
        User GetByUserName(string username);
    }
    
    public class UserRepository : RepositoryBase<User>, IUserRepository
    {
        public User GetByUserName(string username)
        {
            ISession session = GetSession();
            IQuery query = session.CreateQuery("from User u where u.Username = :username");
            query.SetString("username", username);
    
            var matchingUser = query.UniqueResult<User>();
    
            return matchingUser;
        }
    }
    
    
    public class RepositoryBase<T> : IRepository<T> where T : PersistentObject
    {
        public virtual T GetById(object id)
        {
            ISession session = GetSession();
            return session.Get<T>(id);
        }
    
        public virtual T[] GetAll()
        {
            ISession session = GetSession();
            ICriteria criteria = session.CreateCriteria(typeof (T));
            return criteria.List<T>().ToArray();
        }
    
        protected ISession GetSession()
        {
            return new SessionBuilder().GetSession();
        }
    
        public virtual void Save(T entity)
        {
            GetSession().SaveOrUpdate(entity);
        }
    }
    
    public class UserController : ConventionController
    {
        private readonly IUserRepository _repository;
        private readonly ISecurityContext _securityContext;
        private readonly IUserSession _userSession;
    
        public UserController(IUserRepository repository, ISecurityContext securityContext, IUserSession userSession)
        {
            _repository = repository;
            _securityContext = securityContext;
            _userSession = userSession;
        }
    }
    
    public interface IRepository<TKey, TEntity>
    {
        TEntity Get(TKey id);
        void Save(TEntity entity);
    }
    
    public interface IOrderRepository : IRepository<int, Order>
    {
        IEnumerable<Order> GetOrdersByCustomer(Guid customerID);
        IPager<Order> GetOrdersByDate(DateTime fromDate, DateTime toDate);
        IPager<Order> GetOrdersByProduct(int productID);
    }
    
    public class OrderController : Controller
    {
        public OrderController(IOrderRepository orderRepository)
        {
            if (orderRepository == null)
                throw new ArgumentNullException("orderRepository");
            this.OrderRepository = orderRepository;
        }
    
        public ActionResult List(DateTime fromDate, DateTime toDate) { ... }
        // More actions
    
        public IOrderRepository OrderRepository { get; set; }
    }
    
    [TestMethod]
    public void Can_add_order()
    {
        OrderController controller = new OrderController();
        FakeOrderRepository fakeRepository = new FakeOrderRepository();
        controller.OrderRepository = fakeRepository; //<-- Important!
        controller.SubmitOrder(...);
        Assert.That(fakeRepository.ContainsOrder(...));
    }
    
    Bind<ICustomerRepository>().To<LinqToSqlCustomerRepository>();
    Bind<IOrderRepository>().To<LinqToSqlOrderRepository>();
    Bind<IProductRepository>().To<LinqToSqlProductRepository>();
    
    Bind<ICustomerRepository>().To<LinqToSqlCustomerRepository>();
    Bind<IOrderRepository>().To<NHibernateOrderRepository>();
    Bind<IProductRepository>().To<NHibernateProductRepository>();