5

Per qualche motivo Microsoft ha deciso di non supportare il concat semplice in EF5.Il modo migliore per concatenare stringhe e numeri nel server SQL utilizzando Entity Framework 5?

ad es.

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

Questo verrà generato se foo.id o foo.bar sono numeri.

La soluzione che ho trovato è a quanto pare questa bella pezzo di codice:

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

che funziona bene, ma è solo orribile da guardare.

Quindi, c'è un modo decente per realizzare questo con un codice più pulito? NON sono interessato a fare questo lato client, quindi nessuna risposta .AsEnumerable() per favore.

+1

Sono molto confusa sul motivo per cui non avrebbe funzionato ... sei sicuro 'foo' non è' null'? –

+0

Non funziona perché EF non può tradurre integer.ToString() in SQL. –

+0

In questo stadio non penso che abbia nulla a che fare con EF, per quanto riguarda tutto ciò che sta vedendo è un oggetto con una stringa 'someProp'. –

risposta

3

Per chi è interessato. Mi sono così arrabbiato con la mancanza di questa funzionalità che l'ho implementato io stesso utilizzando un ExpressionVisitor.

Ora è possibile scrivere un codice come quello della domanda originale.

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

utilizzo:

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