【问题标题】:Entity framework add a where clause to all queries实体框架向所有查询添加 where 子句
【发布时间】:2012-11-18 00:02:13
【问题描述】:

我正在使用实体框架 5 并使用存储库模式。假设我有这些实体客户、文件、图像、任务、发票、用户。

每个实体(除了客户)都有一个客户外键。当用户登录时,我将 customerid 存储在会话(aps.net mvc)中。我想要的是对所有实体采取的任何 CRUD 都仅限于用户登录的客户。例如,我无法删除属于客户 1 的任务,由来自客户 2 的用户删除。

为每种存储库方法添加 customerid 参数是实现此目的的最佳方法,还是有更好/更聪明的方法?

【问题讨论】:

    标签: asp.net-mvc entity-framework ef-code-first repository


    【解决方案1】:

    很难给出明确的答案,但您可以通过实现更高阶的函数使其更具可扩展性,如下所示:

    public interface IRepository<T>
    {
        public T GetBy(Expression<Func<T, bool>> query)
    }
    
    
    public class FileRepository : IRepository<File>
    {
        public File GetBy(Expression<Func<T, bool>> query)
        {
            using(var context = new FilesContext())
            {
                return context.Files.Where(query).FirstOrDefault();
            }
        }
    
    }
    
    public class SomeController
    {
        private IRepository<File> _repo;
    
        public SomeController(IRepository<File> repo)
        {
            _repo = repo;
        }
    
       public ActionResult Index()
       {
           var model = _repo.GetBy(f => f.CustomerId == Session.Whatever.CustomerId);
    
           return View(model);
       }
    
    }
    

    这样,您可以在需要时更改搜索查询,而不是使用硬编码的客户 ID 属性。例如,如果您想通过 FileID 而不是 CustomerID 获取 File 对象,那么:

    var model = _repo.GetBy(f => f.FileId == someId);
    

    这是代码中唯一需要更改的部分。

    这里有一些关于高阶函数和 C# 函数式编程的非常好的信息:http://www.codeproject.com/Articles/375166/Functional-programming-in-Csharp

    编辑:

    您可以使用装饰器样式模式将“在访问 DB 时始终使用客户 ID”隔离到它自己的存储库中,因此:(ma​​ssive 免责声明 - 我没有对此进行了测试,但是这些方面的东西应该可以工作)

    public class SpecialFileRepo : IRepository<File>
    {
        private readonly IRepository<File> _baseRepo;
    
        public SpecialFileRepo(IRepository<File> baseRepo)
        {
            _baseRepo = baseRepo;
        }
    
        public SpecialFileRepo() : this(new FileRepository())
        {
    
        }
        public File GetBy(Expression<Func<File, bool>> query)
        {
            var parameters = query.Parameters;
            var newParam = Expression.Parameter(typeof (File), "f");
    
            var additionalQuery = Expression.AndAlso(query.Body,
                                                     Expression.Equal(
                                                         Expression.PropertyOrField(newParam, "CustomerId"),
                                                         Expression.Constant(HttpContext.Current.Session["customerId"])));
    
            var newQuery = query.Update(additionalQuery, parameters);
    
    
            return _baseRepo.GetBy(newQuery);
        }
    }
    

    然后任何与存储库对话的东西,就它而言,它只是一个基本存储库,但是这个类位于两者之间,并且总是将“customerid = sessionwhatever”表达式嫁接到最终传递给数据库的内容上。当然,任何只关心使用基础存储库的东西,仍然可以这样做。

    【讨论】:

    • 这行得通,但我想避免把责任留给控制器。我有几个标准控制器、几个 web api 控制器、SignalR 集线器,它们都使用相同的存储库。这意味着我必须确保至少三个位置来限制登录客户对我的实体的访问?
    猜你喜欢
    • 2012-11-27
    • 1970-01-01
    • 1970-01-01
    • 2011-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-21
    • 2010-10-06
    相关资源
    最近更新 更多