存储库模式和LinqToSql方法

时间:2013-10-01 15:01:23

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

我有一个将linq封装到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将属性转换为等效表达式,但是我不喜欢&# 39;我认为我可以在这里做,因为我需要访问datacontext方法。

1 个答案:

答案 0 :(得分:0)

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


是的,我已经设法通过对QueryMap

的一些细微修改来解决这个问题

我需要做两件事才能开始工作:

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

  2. 了解如何通过接口访问querymap以获取在类上定义的属性。

  3. 第一部分相当简单:

    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;
    }
    

    此更改意味着如果我们有一个表示接口方法的member MethodInfo对象,我们将识别出并尝试获取我们正在使用的具体类型的实际MethodInfo (由常量表达式定义)。

    现在,在给定接口的MapToExpressionAttribute的情况下,它正确地获取了实现类的MemberInfo属性。

    下一个问题是使用VisitMethodCall,其中有替换表达式从属性调用失败,因为参数表达式是接口类型,我们调用的方法需要实现类。 / p>

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

    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;
    }