我正在使用实体框架 5 并使用存储库模式。假设我有这些实体客户、文件、图像、任务、发票、用户。
每个实体(除了客户)都有一个客户外键。当用户登录时,我将 customerid 存储在会话(aps.net mvc)中。我想要的是对所有实体采取的任何 CRUD 都仅限于用户登录的客户。例如,我无法删除属于客户 1 的任务,由来自客户 2 的用户删除。
为每种存储库方法添加 customerid 参数是实现此目的的最佳方法,还是有更好/更聪明的方法?
我正在使用实体框架 5 并使用存储库模式。假设我有这些实体客户、文件、图像、任务、发票、用户。
每个实体(除了客户)都有一个客户外键。当用户登录时,我将 customerid 存储在会话(aps.net mvc)中。我想要的是对所有实体采取的任何 CRUD 都仅限于用户登录的客户。例如,我无法删除属于客户 1 的任务,由来自客户 2 的用户删除。
为每种存储库方法添加 customerid 参数是实现此目的的最佳方法,还是有更好/更聪明的方法?
很难给出明确的答案,但您可以通过实现更高阶的函数使其更具可扩展性,如下所示:
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”隔离到它自己的存储库中,因此:(大量免责声明 - 我没有对此进行测试,但这些方面的东西应该可以工作)
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”表达式嫁接到最终传递给数据库的内容上。当然,任何只关心使用基本存储库的东西,仍然可以这样做。