繁体   English   中英

具有缓存和SqlMethods的存储库模式

[英]Repository Pattern with Caching and SqlMethods

我有一个存储库界面,如下所示:

public interface IDataContext<TId> : IDisposable
{
    IQueryable<T> Repository<T>() where T : class, IEntity<TId>;
    T FindById<T>(TId id) where T : class, IEntity<TId>;
    void Insert<T>(T item) where T : class, IEntity<TId>;
    void Delete<T>(T item) where T : class, IEntity<TId>;
    void Commit();
}

请注意, Repository<T>返回一个IQueryable<T>

我有一个可以包装LinqToSQL数据上下文的类,使用Repository<T>方法如下:

public IQueryable<T> Repository<T>() where T : class, IEntity<int>
{
    ITable table = _context.GetTable(GetEntityType<T>());
    return table.Cast<T>();
}

这个工作正常,我可以做类似的事情

new Repository(new SQLDataContext())
    .Repository<MyEntity>().Where(e => SqlMethods.Like(e.Id, "123%");

现在我开始考虑缓存,但是我遇到了问题。

我创建了一个包装和实现IDataContext<TId>的类, IDataContext<TId>将在内存中缓存对Repository<T>调用结果。 类似于以下内容:

public IQueryable<T> Repository<T>() where T : class, IEntity<TId>
{
    // Actual caching logic here.....        

    return _CachedEntities[typeof(T)].OfType<T>().AsQueryable<T>();
}

我遇到的问题是,现在返回的IQueryable<T>是在内存中的,而不是转换为SQL,所以我得到了有关使用SqlMethods.Like的异常。

TL; DR:所以,如何以这样的方式创建我的缓存存储库包装,即调用类不必担心它所处理的IDataContext<T>是否是内存中的存储库(即,缓存中的存储库)还是普通的LinqToSQL存储库?

有可能,您需要编写自定义IQueryProviderIQueryable<T>

public static class MySqlMethods
{
    public static bool Like(string matchExpression, string pattern)
    {
        //Your implementation
        return true;
    }
}

public class ChangeMethodsVisitor : ExpressionVisitor
{
    //This method will change SqlMethods to MySqlMethods.
    protected override Expression VisitMethodCall(MethodCallExpression node)
    {
        if (node.Method.DeclaringType == typeof(SqlMethods))
        {
            //Getting method from MySqlMethods class.
            var method = typeof(MySqlMethods).GetMethod(node.Method.Name,
                                                         node.Method.GetParameters()
                                                             .Select(info => info.ParameterType)
                                                             .ToArray());
            return Expression.Call(method, node.Arguments);
        }
        return base.VisitMethodCall(node);
    }
}

public class MyQueryProvider : IQueryProvider
{
    private static readonly ExpressionVisitor ExpressionVisitor = new ChangeMethodsVisitor();
    private readonly IQueryProvider _queryProvider;

    public MyQueryProvider(IQueryProvider queryProvider)
    {
        _queryProvider = queryProvider;
    }

    public IQueryable CreateQuery(Expression expression)
    {
        expression = ExpressionVisitor.Visit(expression);
        var queryable = _queryProvider.CreateQuery(expression);
        //Wrap queryable to MyQuery class.
        var makeGenericType = typeof(MyQuery<>).MakeGenericType(queryable.ElementType);
        return (IQueryable)makeGenericType.GetConstructor(new[] { typeof(IQueryable<>).MakeGenericType(queryable.ElementType) })
                                           .Invoke(new object[] { queryable });
    }

    public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
    {
        expression = ExpressionVisitor.Visit(expression);
        //Wrap queryable to MyQuery class.
        var queryable = _queryProvider.CreateQuery<TElement>(expression);
        return new MyQuery<TElement>(queryable);
    }

    public object Execute(Expression expression)
    {
        expression = ExpressionVisitor.Visit(expression);
        return _queryProvider.Execute(expression);
    }

    public TResult Execute<TResult>(Expression expression)
    {
        expression = ExpressionVisitor.Visit(expression);
        return _queryProvider.Execute<TResult>(expression);
    }
}

public class MyQuery<T> : IOrderedQueryable<T>
{
    private readonly IQueryable<T> _queryable;

    public MyQuery(IQueryable<T> queryable)
    {
        _queryable = queryable;
        Provider = new MyQueryProvider(_queryable.Provider);
    }

    public MyQuery(IEnumerable<T> enumerable)
        : this(enumerable.AsQueryable())
    {
    }

    public IEnumerator<T> GetEnumerator()
    {
        return _queryable.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public Expression Expression
    {
        get { return _queryable.Expression; }
    }

    public Type ElementType
    {
        get { return _queryable.ElementType; }
    }

    public IQueryProvider Provider { get; private set; }
}

然后您可以使用它:

var list = new List<string>(){"test", "test1"};

var myQuery = new MyQuery<string>(list);
var queryable = myQuery.Where(s => SqlMethods.Like(s, "123%")).ToArray();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM