LINQ查询失败,可以使用可变的ormlite

时间:2015-06-11 10:41:07

标签: linq servicestack ormlite-servicestack

我尝试使用ServiceStack Ormlite编写以下LINQ查询。

dbConn.Select<Product>(p => p.IsActive.HasValue && p.IsActive.Value)

在这里,产品是我的项目类,&#34; IsActive&#34;是该类中的Nullable Bool属性。当该行执行时,它总是抛出&#34; InvalidOperationException&#34;消息

变量&#39; p&#39;类型&#39;&#39;引用范围&#39;&#39;,但未定义

我尝试了以下不同的变体,但仍有相同的异常结果

dbConn.Select<Product>(p => p.IsActive.HasValue == true && p.IsActive.Value == true)
dbConn.Select<Product>(p => p.IsActive != null && p.IsActive.Value == true)

但如果我只是写

dbConn.Select<Product>(p => p.IsActive.HasValue)

然后它有效。

我很困惑,问题是什么?这是servicestack ormlite问题吗?

2 个答案:

答案 0 :(得分:2)

我的回答可以使用servicestack ormlite处理Nullable值,例如“value”和“HasValue”。而且还有datetime可空,比如'createdate.value.Year'。 你必须改变两个的地方。

  1. 修改VisitMemberAccess方法:
  2. protected virtual object VisitMemberAccess(MemberExpression m)
            {
                if (m.Expression != null)
                {
                     if (m.Member.DeclaringType.IsNullableType())
                     {
                        if (m.Member.Name == nameof(Nullable<bool>.Value))
                            return Visit(m.Expression);
                        if (m.Member.Name == nameof(Nullable<bool>.HasValue))
                        {
                            var doesNotEqualNull = Expression.NotEqual(m.Expression, Expression.Constant(null));
                                return Visit(doesNotEqualNull); // Nullable<T>.HasValue is equivalent to "!= null"
                        }
                        throw new ArgumentException(string.Format("Expression '{0}' accesses unsupported property '{1}' of Nullable<T>", m, m.Member));
                    }
                    if (m.Member.DeclaringType == typeof(DateTime))
                    {
                        var ExpressionInfo = m.Expression as MemberExpression;
                        if (ExpressionInfo.Member.DeclaringType.IsNullableType())
                        {
                            if (ExpressionInfo.Member.Name == nameof(Nullable<bool>.Value))
                            {
                                var modelType = (ExpressionInfo.Expression as MemberExpression).Expression.Type;
                                var tableDef = modelType.GetModelDefinition();
                                var columnName = (ExpressionInfo.Expression as MemberExpression).Member.Name;
                                var QuotedColumnName = GetQuotedColumnName(tableDef, columnName);
                                if (m.Member.Name == "Year")
                                {
                                    return new PartialSqlString(string.Format("DATEPART(yyyy,{0})", QuotedColumnName));
                                }
                                if (m.Member.Name == "Month")
                                    return new PartialSqlString(string.Format("DATEPART(mm,{0})", QuotedColumnName));
                            }                            
                            if (ExpressionInfo.Member.Name == nameof(Nullable<bool>.HasValue))
                            {
                                var doesNotEqualNull = Expression.NotEqual(ExpressionInfo.Expression, Expression.Constant(null));
                                return Visit(doesNotEqualNull); // Nullable<T>.HasValue is equivalent to "!= null"
                            }
                        }
                        else
                        {
                            var modelType = ExpressionInfo.Expression.Type;
                            var tableDef = modelType.GetModelDefinition();
                            var columnName = ExpressionInfo.Member.Name;
                            var QuotedColumnName = GetQuotedColumnName(tableDef, columnName);
                            if (m.Member.Name == "Year")
                                return new PartialSqlString(string.Format("DATEPART(yyyy,{0})", QuotedColumnName));
                            if (m.Member.Name == "Month")
                                return new PartialSqlString(string.Format("DATEPART(mm,{0})", QuotedColumnName));
                        }
                    }
                    if (m.Expression.NodeType == ExpressionType.Parameter || m.Expression.NodeType == ExpressionType.Convert)
                    { 
                        var propertyInfo = (PropertyInfo)m.Member;
    
                        var modelType = m.Expression.Type;
                        if (m.Expression.NodeType == ExpressionType.Convert)
                        {
                            var unaryExpr = m.Expression as UnaryExpression;
                            if (unaryExpr != null)
                            {
                                modelType = unaryExpr.Operand.Type;
                            }
                        }
    
                        var tableDef = modelType.GetModelDefinition();
                        if (propertyInfo.PropertyType.IsEnum)
                            return new EnumMemberAccess(
                                GetQuotedColumnName(tableDef, m.Member.Name), propertyInfo.PropertyType);
    
                        return new PartialSqlString(GetQuotedColumnName(tableDef, m.Member.Name));
                    }
                }
    
                var member = Expression.Convert(m, typeof(object));
                var lambda = Expression.Lambda<Func<object>>(member);
                var getter = lambda.Compile();
                return getter();
            }

    1. 修改VisitLambda方法
    2. protected virtual object VisitLambda(LambdaExpression lambda)
              {
                  if (lambda.Body.NodeType == ExpressionType.MemberAccess && sep == " ")
                  {
                      MemberExpression m = lambda.Body as MemberExpression;
      
                      if (m.Expression != null)
                      {
                          string r = VisitMemberAccess(m).ToString();
                          if (m.Member.DeclaringType.IsNullableType())
                              return r;
                          return string.Format("{0}={1}", r, GetQuotedTrueValue());
                      }
      
                  }
                  return Visit(lambda.Body);
              }

答案 1 :(得分:1)

这是Linq的本质。为了达到你所需要的,你需要使用两个关闭的地方:

public void CreateSaveFile(string fileName, TreeView treeView)
{
    using (StreamWriter streamWriter = new StreamWriter(fileName))
    {
        // Print each node recursively.
        TreeNodeCollection nodes = treeView.Nodes;
        foreach (TreeNode n in nodes)
        {
            WriteRecursive(streamWriter, n);
        }
        streamWriter.Close(); // Optional since we have "using", but good practice to include.
    }
}