2013-09-03 35 views
5

Vì một lý do nào đó, Microsoft quyết định không hỗ trợ concat đơn giản trong EF5.Cách tốt nhất để ghép chuỗi và số trong máy chủ SQL bằng Entity Framework 5?

ví dụ:

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

Điều này sẽ ném nếu foo.id hoặc foo.bar là số.

Cách giải quyết tôi đã tìm thấy là dường như mảnh khá mã này:

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

nào hoạt động tốt, nhưng chỉ là khủng khiếp để xem xét.

Vì vậy, có cách nào tốt để thực hiện điều này bằng mã sạch hơn không? Tôi KHÔNG quan tâm đến phía khách hàng này, vì vậy không, vui lòng trả lời .AsEnumerable().

+1

Tôi rất bối rối là tại sao điều đó sẽ không làm việc ... bạn có chắc 'foo' không phải là' null'? –

+0

Nó không hoạt động vì EF không thể dịch integer.ToString() thành SQL. –

+0

Tôi không nghĩ rằng đó là bất cứ điều gì để làm với EF ở giai đoạn này như xa như nó liên quan đến tất cả nó được nhìn thấy là một đối tượng với một chuỗi 'someProp'. –

Trả lời

3

Đối với những người quan tâm. Tôi đã rất tức giận vì thiếu tính năng này mà tôi đã tự mình triển khai bằng ExpressionVisitor.

Bây giờ bạn có thể viết mã giống như mã trong câu hỏi gốc.

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

sử dụng:

var res = model 
    .FooSet 
    .Extend() //<- applies the magic 
    .Select(foo => new 
     { 
     someProp = "hello" + foo.id + "/" + foo.bar 
     } 
Các vấn đề liên quan