2013-09-03 12 views
5

Aus irgendeinem Grund hat Microsoft beschlossen, einfache Concat in EF5 nicht zu unterstützen.Die beste Möglichkeit, Strings und Zahlen in SQL Server mit Entity Framework 5 zu erstellen?

z.B.

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

Dies wird ausgelöst, wenn foo.id oder foo.bar Zahlen sind.

Die Abhilfe, die ich gefunden habe, ist dies offenbar ziemlich peice Code:

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

der gut arbeitet, aber nur schrecklich zu sehen.

Also, gibt es einen anständigen Weg, dies mit sauberer Code zu erreichen? Ich bin nicht daran interessiert, diese Client-Seite zu tun, also keine .AsEnumerable() Antworten bitte.

+1

ich sehr verwirrt bin, warum das nicht funktionieren würde ... sind Sie sicher, 'foo' ist nicht 'null'? –

+0

Es funktioniert nicht, weil EF integer.ToString() nicht in SQL übersetzen kann. –

+0

Ich glaube nicht, dass es in diesem Stadium etwas mit EF zu tun hat, soweit es darum geht, dass es nur ein Objekt mit einer Zeichenkette 'someProp' ist. –

Antwort

3

Für diejenigen interessiert. Ich war so sauer wegen des Fehlens dieses Features, dass ich es selbst mit einem ExpressionVisitor implementiert habe.

Sie können nun Code wie den in der ursprünglichen Frage schreiben.

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

Nutzung:

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