【问题标题】:asp.net mvc data logic structureasp.net mvc数据逻辑结构
【发布时间】:2014-03-02 16:08:13
【问题描述】:

所以我有一堆实体模型。

许多控制器和视图,并且控制器经常去执行 linq 查询并使其可用于视图。

但是假设我有一个模型用户

我有一个 linq 查询来获取所有活跃用户

如果只完成一次,将其放入控制器中可能会很好,但我想重复一遍,我想知道放置模型特定查询的正确位置。

理想情况下,控制器会说 Users.getActiveUsers() 或类似内容。

【问题讨论】:

  • 我认为您正在寻找的是repository pattern。然后你有一个IRepository<EntityType> 和一个IQueryable<T> Get(System.Func<T, Boolean> Query) 方法...UserRepo.Get(u=>u.Username == "Bob")
  • 一般来说,这种类型的操作应该作为模型的函数或在存储库中处理。我通常倾向于存储库模式。

标签: c# asp.net asp.net-mvc linq asp.net-mvc-4


【解决方案1】:

您应该查看存储库模式。

存储库模式允许您抽象此数据库逻辑并减少常见数据调用的冗余。既然您经常编写 LINQ 查询,为什么不将它们放在一个通用类中呢?

public class UserRepository 
{
     private readonly _dbContext MyDbContext;

     public IEnumberable<User> getActiveUsers() 
     {
          // whatever you do to find the active users
          return _dbContext.Where(user => user.Active == true);
     }
}

现在您可以将此存储库注入到您的控制器中。

public class HomeController : Controller
{
     private readonly UserRepository _userRepo;

     public HomeController()
     {
         _userRepo = new UserRepository();
     }

     public ActionResult Index()
     {
          var activeUsers = _userRepo.getActiveUsers();

          return View(activeUsers);
     }
}

上述实现将解决您的问题,但它确实将您的控制器与您的存储库紧密耦合。解耦它们的解决方案是使用 UserRepository 的接口,然后使用依赖注入(使用 Ninject、Unity、AutoFaq 或其他)来解析接口的类型。

【讨论】:

    【解决方案2】:

    我建议将数据访问逻辑移动到单独的类 (repositories),这些类将充当实体的内存集合并隐藏所有数据访问逻辑。例如。如果您有实体User,您可以创建存储库,该存储库将封装与用户相关的所有 linq 查询:

    public class UserRepository : IUserRepository
    {
        private YourDbContext _db;     
    
        public UserRepository(YourDbContext db)
        {
            _db = db;
        }
    
        public User GetById(int id)
        {
            return _db.Users.Find(id);
        }
    
        public IEnumerable<User> GetAll()
        {
            return _db.Users.AsEnumerable();
        }
    
        public IEnumerable<User> GetUsersByRole(string role)
        {
            return _db.Users.Where(u => u.Role == role).AsEnumerable();
        }
    }
    

    这会将所有数据访问代码保存在一个位置,不会重复。当您添加另一个存储库时,您会发现一些重复的逻辑(例如,通过 id 获取实体,或获取所有实体)可以移动到基础 generic repository 类。

    我还建议依赖控制器中的存储库接口:

    public interface IUserRepository
    {
        User GetById(int id);
        IEnumerable<User> GetAll();
        IEnumerable<User> GetUsersByRole(string role);
    }
    

    这将使控制器的单元测试变得非常容易(模拟存储库和注入模拟):

    public class UserController : Controller
    {
        private readonly IUserRepository _userRepository;
    
        public UserController(IUserRepository userRepository)
        {
            _userRepository = userRepository;
        }
    
        public ActionResult Index()
        {
            // Note: usually you should not use entities in view 
            // create appropriate view models and map entities to them
            var model = _userRepository.GetAll();
            return View(model);
        }
    }
    

    【讨论】:

    • 如果您的所有实体都继承自一个公共类,您可以创建一个通用存储库(和接口),而无需重用代码。在我的例子中,我将 Id 字段放在基类中,这意味着它可以用于与实体无关的目的。
    • @Basic 我经常以基本实体类结束,但并非总是如此。如果您的实体具有不同类型的身份字段(int、long、guid)甚至是复合身份,那么基类将无济于事
    • 非常正确。我只是指出 OP 可能会获胜,但你是对的,它绝对不适合所有情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-03
    • 2017-01-10
    • 2011-02-25
    • 2011-02-20
    • 2015-04-01
    • 1970-01-01
    • 2012-01-26
    相关资源
    最近更新 更多