我可以在选择时让我的实体框架DbSet调用我的表值函数吗?

时间:2017-12-12 15:11:57

标签: entity-framework entity-framework-6 ef-code-first

我有许多使用DbSet<dbo_Deal>的现有查询,现在要求过滤未经授权用户的机密交易。我想知道是否有一种覆盖DbSet<dbo_Deal>的方法,以便它选择使用Table Valued参数而不是默认行为。

如果用户没有访问权限,我创建了以下过滤掉机密交易的TVF:

CREATE FUNCTION [dbo].[GetDeals](@UserKey int)
RETURNS TABLE
RETURN (
    SELECT d.*
    FROM dbo.Deal d
    WHERE d.Confidentiality = 0
    OR EXISTS(SELECT *
                FROM dbo.UserRole ur
                WHERE ur.UserKey = @UserKey
                AND ur.Role = 'Admin')
);

我还在DbContext中添加了以下内容来调用SQL函数:

[DbFunction("MyDbContext", "GetDeals")]
[CodeFirstStoreFunctions.DbFunctionDetails(DatabaseSchema = "dbo")]
public IQueryable<dbo_Deal> GetDeals()
{
    var userKeyParam = new System.Data.Entity.Core.Objects.ObjectParameter("UserKey", typeof(int)) { Value = _userKey };
    return ((System.Data.Entity.Infrastructure.IObjectContextAdapter)this).ObjectContext.CreateQuery<dbo_Deal>("[MyDbContext].[GetDeals](@UserKey)", userKeyParam);
}

我知道我可以重构我的所有查询来调用这个函数,但是如果我能够以某种方式指示Entity Framework在选择或加入Deals时使用此函数,那将会很棒。这可能吗?

2 个答案:

答案 0 :(得分:0)

尝试Moq DbSet

public class YourContext: DbContext
{
    public YourContext()
    {
        var tvf = GetDeals();

        var mockSet = new Mock<DbSet<dbo_Deal>>();      

        mockSet.As<IQueryable<dbo_Deal>>().Setup(m => m.Provider).Returns(tvf.Provider);
        mockSet.As<IQueryable<dbo_Deal>>().Setup(m => m.Expression).Returns(tvf.Expression);
        mockSet.As<IQueryable<dbo_Deal>>().Setup(m => m.ElementType).Returns(tvf.ElementType);
        mockSet.As<IQueryable<dbo_Deal>>().Setup(m => m.GetEnumerator()).Returns(() => tvf.GetEnumerator());        

        //your DbSet:
        dbo_Deals = mockSet.Object;
    }   
}

答案 1 :(得分:0)

我无法按照我想要的方式使用SQL函数获得解决方案,所以我使用了包含DbSet的FilteredDbSet。我必须做的就是在DbContext中为我的属性创建一个返回类型a public class FilteredDbSet<TEntity> : IDbSet<TEntity>, IOrderedQueryable<TEntity>, IListSource where TEntity : class { private readonly DbSet<TEntity> _set; private readonly Action<TEntity> _initializeEntity; private readonly Expression<Func<TEntity, bool>> _filter; public FilteredDbSet(DbContext context, Expression<Func<TEntity, bool>> filter, Action<TEntity> initializeEntity) : this(context.Set<TEntity>(), filter, initializeEntity) { } public IQueryable<TEntity> Include(string path) { return _set.Include(path).Where(_filter).AsQueryable(); } private FilteredDbSet(DbSet<TEntity> set, Expression<Func<TEntity, bool>> filter, Action<TEntity> initializeEntity) { _set = set; _filter = filter; _initializeEntity = initializeEntity; } public IQueryable<TEntity> Unfiltered() { return _set; } public TEntity Add(TEntity entity) { DoInitializeEntity(entity); return _set.Add(entity); } public void AddOrUpdate(TEntity entity) { DoInitializeEntity(entity); _set.AddOrUpdate(entity); } public TEntity Attach(TEntity entity) { DoInitializeEntity(entity); return _set.Attach(entity); } public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, TEntity { var entity = _set.Create<TDerivedEntity>(); DoInitializeEntity(entity); return entity; } public TEntity Create() { var entity = _set.Create(); DoInitializeEntity(entity); return entity; } public TEntity Find(params object[] keyValues) { var entity = _set.Find(keyValues); if (entity == null) return null; return entity; } public TEntity Remove(TEntity entity) { if (!_set.Local.Contains(entity)) { _set.Attach(entity); } return _set.Remove(entity); } public ObservableCollection<TEntity> Local { get { return _set.Local; } } IEnumerator<TEntity> IEnumerable<TEntity>.GetEnumerator() { return _set.Where(_filter).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return _set.Where(_filter).GetEnumerator(); } Type IQueryable.ElementType { get { return typeof(TEntity); } } Expression IQueryable.Expression { get { return _set.Where(_filter).Expression; } } IQueryProvider IQueryable.Provider { get { return _set.AsQueryable().Provider; } } bool IListSource.ContainsListCollection { get { return false; } } IList IListSource.GetList() { throw new InvalidOperationException(); } void DoInitializeEntity(TEntity entity) { if (_initializeEntity != null) _initializeEntity(entity); } public DbSqlQuery<TEntity> SqlQuery(string sql, params object[] parameters) { return _set.SqlQuery(sql, parameters); } } ,然后使用我想要的过滤器在构造函数中实例化它。我还在下面公开的类中创建了私有构造函数,因此我可以模拟它进行单元测试。

这对我来说是一个非常好的解决方案,因为我避免重构所有现有的Linq查询,并且任何将来的查询都会自动获得此行为。

$scope.$watch('scopeVariable', function() {
    alert('scopeVariable has changed');
});