【问题标题】:The repository pattern and LinqToSql methods存储库模式和 LinqToSql 方法
【发布时间】:2013-10-07 19:35:31
【问题描述】:

我有一个封装 linq to sql 数据上下文的对象。

它有一个方法IQuerable<T> FromStore<T>,允许我通过 linq 到 sql 从适当的表中获取我的实体。

我也有调用数据上下文中函数的调用方法。

我现在遇到的问题是我不能在 where 子句中使用那些通过方法,因为没有对 sql 的翻译。我明白为什么会发生这种情况,但我该如何解决呢?


示例代码:

在我的存储库类中:

public class AquaReportsRepository : LinqToSqlRepository<int>, IAquaReportsRepository
{
    public bool IsPhysicalItem(string itemNumber)
    {
        return _UnderlyingDataContext.Aqua_IsPhysicalItem(itemNumber) ?? true;
    }
}

尝试从中访问数据:

from part in Repository.FromStore<Parts>()
where !(Repository.IsPhysicalItem(part.Item)) // eek, not translation to sql
select part.ItemNumber;

过去,我需要数据对象上的一个简单属性,该属性是从另一个属性计算出来的,我使用QueryMap 将该属性转换为等效表达式,但是我认为我做不到在这里,因为我需要访问 datacontext 方法。

【问题讨论】:

    标签: c# linq linq-to-sql repository-pattern


    【解决方案1】:

    TL;DR:阅读第 1 点的示例。使用 QueryMap 中的代码,在下面以粗体进行更改。


    好的,我已经设法通过对 QueryMap 进行一些细微修改来解决这个问题

    我需要做两件事:

    1. 弄清楚如何告诉 querymap 调用使用数据上下文的方法?

    2. 当通过接口访问时,弄清楚如何让 querymap 获取定义在类上的属性。

    第一部分相当简单:

    private static readonly ExpressionMethod<Func<AquaReportsRepository, string, bool>> _IsPhysicalItem =
        ExpressionMethod.Create((AquaReportsRepository ardc, string i) => ardc._AquaReportsDC.Aqua_IsPhysicalItem(i) ?? true);
    
    [MapToExpression("_IsPhysicalItem")]
    public bool IsPhysicalItem(string itemNumber)
    {
        return _IsPhysicalItem.Invoke(this, itemNumber);
    }
    

    这里的关键是简单地使用一个函数,该函数将对象本身作为第一个参数(在这种情况下为AquaReportsRepository),以及正常的其他参数。

    然而,第二部分需要对MappedQueryVisitor.cs 进行一些(相当小的)更改。在这两种情况下,只有一个 if 语句(里面有语句!)。

    用这个替换现有的GetLambda 方法

    private LambdaExpression GetLambda(Expression receiver, MemberInfo member) {
    
        LambdaExpression exp;
        if(!_mappings.TryGetValue(member, out exp)) {
            exp = _mappingLookup(member);
            if(null == exp) {
                var attr = (MapToExpressionAttribute) member.GetCustomAttributes(typeof(MapToExpressionAttribute), true).FirstOrDefault();
    
                // Added by me to deal with interfaces
                if (null == attr)
                {
                    if (null != receiver)
                    {
                        // member could be an interface's member, so check the receiver.object type
                        if (receiver.NodeType == ExpressionType.Constant)
                        {
                            var receiverType = ((ConstantExpression)receiver).Value.GetType();
    
                            var receiverMemberInfo = receiverType.GetMembers().Where(mi => mi.Name == member.Name).SingleOrDefault();
    
                            if (null != receiverMemberInfo)
                            {
                                attr = (MapToExpressionAttribute)receiverMemberInfo.GetCustomAttributes(typeof(MapToExpressionAttribute), true).FirstOrDefault();
                                member = receiverMemberInfo;
                            }
                        }
                    }
                }
    
    
                if(null != attr) {
                    exp = GetLambdaFromAttribute(receiver, member.DeclaringType, attr);
                }
            }
            _mappings.Add(member, exp);
        }
        return exp;
    }
    

    这种变化意味着如果我们有一个代表接口方法的memberMethodInfo对象,我们将识别它并尝试获取我们正在使用的具体类型的实际MethodInfo(由常量表达式定义)。

    现在它正确地获取了实现类上的MapToExpressionAttribute 属性,给定一个接口的MemberInfo

    下一个问题是VisitMethodCall,从属性调用替换表达式失败了,因为参数表达式是接口类型,通过我们调用的方法需要实现类。

    最后的代码更改纠正了这一点。

    CollectArguments方法改成这样

    private static IEnumerable<Expression> CollectArguments(MethodCallExpression m) {
        IEnumerable<Expression> args = m.Arguments;
        if (!m.Method.IsStatic)
        {
            var objectExpression = m.Object;
    
            // Added by me, to deal with interfaces
            if (objectExpression.NodeType == ExpressionType.Constant)
            {
                var objectConstExpression = ((ConstantExpression)objectExpression);
    
                if (objectConstExpression.Type.IsInterface)
                {
                    objectExpression = Expression.Constant(objectConstExpression.Value);
                }
            }
    
            args = Enumerable.Repeat(objectExpression, 1).Concat(args);
        }
        return args;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-30
      • 1970-01-01
      • 2012-08-22
      • 1970-01-01
      • 1970-01-01
      • 2011-02-10
      • 2023-04-10
      • 1970-01-01
      相关资源
      最近更新 更多