2013-09-03 21 views
5

Z jakiegoś powodu Microsoft zdecydował się nie obsługiwać prostych konkatencji w wersji EF5.Najlepszy sposób łączenia łańcuchów i liczb w serwerze SQL za pomocą Entity Framework 5?

np.

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

Spowoduje to wyświetlenie, jeśli foo.id lub foo.bar są liczbami.

Obejście Znalazłem ten jest najwyraźniej dość peice kodu:

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

Które działa dobrze, ale jest po prostu okropny patrzeć.

Czy jest jakiś przyzwoity sposób, aby osiągnąć ten cel przy użyciu czystszego kodu? Nie jestem zainteresowany wykonaniem tej strony klienta, więc nie proszę odpowiedzi .AsEnumerable().

+1

jestem bardzo mylić, dlatego, że nie będzie działać ... jesteś pewny 'foo' nie jest' null'? –

+0

To nie działa, ponieważ EF nie może przetłumaczyć liczby całkowitej.ToString() na SQL. –

+0

Nie sądzę, że ma to związek z EF na tym etapie, o ile chodzi o to, że jest to obiekt z ciągiem 'someProp'. –

Odpowiedz

3

Dla zainteresowanych. Wkurzyłem się z braku tej funkcji, którą sam zaimplementowałem za pomocą ExpressionVisitor.

Możesz teraz pisać kod taki jak oryginalny.

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

Wykorzystanie:

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