5

何らかの理由で、マイクロソフトはEF5で単純なコンカットをサポートしないことに決めました。Entity Framework 5を使用しているSQLサーバーの文字列と数値を連結する最適な方法は?

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() 
      } 

私が見つけた回避策

は明らかにこのコードのかなりpeiceです。

これで、よりクリーンなコードでこれを実現する方法がありますか? 私はこのクライアント側に興味がないので、.AsEnumerable()は答えません。

+1

私はそれが動作しない理由としては非常に混乱しています... 'foo'は' null'なのでではありませんあなたは確かにありますか? –

+0

EFはinteger.ToString()をSQLに変換できないため、機能しません。 –

+0

文字列 'someProp'を持つオブジェクトが見えている限り、この段階ではEFとは何の関係もないと思います。 –

答えて

3

興味のある方 私は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 
     } 
関連する問題