使用EntityFramework5在SQL server中连接字符串和数字的最佳方式

本文关键字:数字 最佳 方式 字符串 连接 EntityFramework5 SQL server 使用 | 更新日期: 2023-09-27 18:30:04

由于某些原因,Microsoft决定不支持EF5中的简单concat。

例如

Select(foo => new 
           {
             someProp = "hello" + foo.id + "/" + foo.bar
           }

如果foo.id或foo.bar是数字,就会抛出。

我找到的解决方法显然是这个漂亮的代码:

Select(foo => new 
           {
             someProp = "hello" + 
             SqlFunctions.StringConvert((double?)foo.id).Trim()  + 
             "/" + 
             SqlFunctions.StringConvert((double?)foo.bar).Trim() 
           }

这很好用,但看起来很可怕。

那么,有没有什么像样的方法可以用更干净的代码来实现这一点呢?我对做这个客户端不感兴趣,所以没有。请回答AsEnumerable()。

使用EntityFramework5在SQL server中连接字符串和数字的最佳方式

对于感兴趣的人。我对缺少这个功能感到非常恼火,所以我自己使用ExpressionVisitor实现了它。

现在,您可以像原来问题中那样编写代码。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Objects.SqlClient;
using System.Linq;
using System.Linq.Expressions;
namespace Crawlr.Web.Code
{
    public static class ObjectSetExExtensions
    {
        public static ObjectSetEx<T> Extend<T>(this IQueryable<T> self) where T : class
        {
            return new ObjectSetEx<T>(self);
        }
    }
    public class ObjectSetEx<T> : IOrderedQueryable<T>
    {
        private readonly QueryProviderEx provider;
        private readonly IQueryable<T> source;
        public ObjectSetEx(IQueryable<T> source)
        {
            this.source = source;
            provider = new QueryProviderEx(this.source.Provider);
        }
        #region IQueryableEx<T> Members
        public IEnumerator<T> GetEnumerator()
        {
            return source.GetEnumerator();
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return source.GetEnumerator();
        }
        public Type ElementType
        {
            get { return source.ElementType; }
        }
        public Expression Expression
        {
            get { return source.Expression; }
        }
        public IQueryProvider Provider
        {
            get { return provider; }
        }
        #endregion
    }
    public class QueryProviderEx : IQueryProvider
    {
        private readonly IQueryProvider source;
        public QueryProviderEx(IQueryProvider source)
        {
            this.source = source;
        }
        #region IQueryProvider Members
        public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
        {
            Expression newExpression = ExpressionReWriterVisitor.Default.Visit(expression);
            IQueryable<TElement> query = source.CreateQuery<TElement>(newExpression);
            return new ObjectSetEx<TElement>(query);
        }
        public IQueryable CreateQuery(Expression expression)
        {
            Expression newExpression = ExpressionReWriterVisitor.Default.Visit(expression);
            IQueryable query = source.CreateQuery(newExpression);
            return query;
        }
        public TResult Execute<TResult>(Expression expression)
        {
            Expression newExpression = ExpressionReWriterVisitor.Default.Visit(expression);
            return source.Execute<TResult>(newExpression);
        }
        public object Execute(Expression expression)
        {
            Expression newExpression = ExpressionReWriterVisitor.Default.Visit(expression);
            return source.Execute(newExpression);
        }
        #endregion
    }
    public class ExpressionReWriterVisitor : ExpressionVisitor
    {
        public static readonly ExpressionReWriterVisitor Default = new ExpressionReWriterVisitor();
        protected override Expression VisitUnary(UnaryExpression node)
        {
            if (node.NodeType == ExpressionType.Convert && node.Operand.Type == typeof(int) && node.Type==typeof(object))
            {
                var operand = node.Operand;
                var stringConvertMethod = typeof(SqlFunctions).GetMethod("StringConvert", new Type[] { typeof(double?) });
                var trimMethod = typeof(string).GetMethod("Trim",new Type[] {});

                var dOperand = Expression.Convert(operand, typeof(double?));
                return Expression.Call(Expression.Call(stringConvertMethod, dOperand),trimMethod);
            }
            return base.VisitUnary(node);
        }      
    }
}

用法:

  var res = model
  .FooSet
  .Extend() //<- applies the magic
  .Select(foo => new 
       {
         someProp = "hello" + foo.id + "/" + foo.bar
       }