使用当前用户过滤器编写第一个DbContext代码

时间:2011-09-20 21:20:46

标签: asp.net-mvc-3 ef-code-first

我正在构建一个带有代码优先数据库的ASP.NET MVC3网站,并提出以下问题:

是否可以使用附加参数集创建MyDbContext类的实例,该参数集将用于过滤对mydbcontext的调用结果。

我想用它来将结果集限制为在我的asp.net mvc网站上登录的当前用户。

任何指示都会很棒!

3 个答案:

答案 0 :(得分:1)

我不明白为什么这应该是一个问题。这样的事情应该有效:

public class Northwind : DbContext
{
    public DbSet<Product> Products { get; set; }
    public DbSet<Category> Categories { get; set; }
}

public class FilteredNorthwind : Northwind
{
   public IQueryable<Products> GetFilteredProducts(string userRole)
   {
        return Products.Where(product => product.UserRole == userRole);
   }
}

<强>更新

为了使您的MyDbContext无法被滥用,您可以将所有数据库代码和模型放入单独的项目/程序集中。然后将DbContext设为internal课程(而不是public),然后创建一个包裹publicFilteredDbContext的{​​{1}}课程(MyDbContext)公开允许您只获取允许查看的数据的方法。然后在主程序集(您的Web项目)中,您将只能使用FilteredDbContext

所以,例如:

internal class Northwind : DbContext // note: internal class
{
    public DbSet<Product> Products { get; set; }
    public DbSet<Category> Categories { get; set; }
}

public class FilteredNorthwind // note: does not inherit from `Northwind`
{
   private readonly _dbContext = new Northwind();

   public IQueryable<Products> GetProducts(string userRole)
   {
        return _dbContext.Products.Where(product => product.UserRole == userRole);
   }
}

如果NorthwindFilteredNorthwind与您的网络应用程序位于不同的程序集中,则只能从您的网络应用程序中实例化FilteredNorthwind

更新2

如果您使用ViewModel,那么您的网络应用程序无法返回到某个类别的所有产品列表,因为您只提取了所需的属性(并且只提取了允许用户查看的属性)。 / p>

public class ProductViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

public IEnumerable<Products> GetProducts(string userRole)
{
    return _dbContext.Products
        .Where(product => product.UserRole == userRole)
        .Select(product => new ProductViewModel
        {
            Id = product.Id,
            Name = product.Name,
            Price = product.Price
        };
}

答案 1 :(得分:0)

您可以在上面创建一个图层并隐藏生成的图层并创建一个您自己的DbContext,它源自生成的MyDbContext。只是一个疯狂的猜测,但它似乎合乎逻辑,所以你可以实现自己的参数集,仍然使用生成的参数集。

答案 2 :(得分:0)

我会这样做:

public interface IUserContext {
    string User { get; set; }
}

public class Database : DbContext {
    public IDbSet<Product> Products { get; set; }
}

public class AuthorizedDatabase {
    private readonly Database _database;
    private readonly IUserContext _userContext;

    public AuthorizedDatabase(Database database, IUserContext userContext) {
        _database = database;
        _userContext = userContext;
    }

    private bool Authorize<TEntity>(TEntity entity) {
        // Some code here to look at the entity and the _userContext and decide if it should be accessible.
    }

    public IQueryable<Product> Products {
        get {
            return _database.Products.Where(Authorize);
        }
    }    
}

这将允许我干净地抽象出授权周围的实际逻辑(并且您的IUserContext接口可以根据您的确切需求进行简单或复杂的处理。)

要确保用户无法使用导航属性(例如,Product.Category.Products)绕过此保护,您可能需要关闭延迟加载并显式加载所需的相关实体。

从ADO.NET团队博客中查看此帖子的想法:loading related entities