2011-03-20 113 views
17

我有以下查詢:實體框架4/Linq:如何將DateTime轉換爲查詢中的字符串?

from a in Products 
select new ProductVM 
    { 
     id = a.id, 
     modified = a.modified.ToString() 
    } 

這給了我一個錯誤:

LINQ to Entities does not recognize the method 'System.String ToString()' 
method, and this method cannot be translated into a store expression. 

產品表是日期時間的modified。 ProductVM類中的modified是字符串。

任何想法?這必須是一個微不足道的問題。

回答

19

ToString() Linq to Entities不支持 - 有一個函數助手列表作爲SqlFunctions的一部分,但是這不支持日期到字符串轉換。

最簡單的將是第一個項目在查詢中匿名類型,然後使用AsEnumerable()強制轉換爲IEnumerable - 之後,你可以因爲你現在使用LINQ爲查詢表達式的其餘對象使用ToString()(有關於此主題的冗長的文章here)。

var results = Products.Select(p => new { a.id, a.modified }) 
         .AsEnumerable() 
         .Select(p => new ProductVM() 
           { id = p.id, 
            modified = p.modified.ToString() 
           }); 
+0

太棒了。我剛剛使用了我的POCO,然後在最後一分鐘使用了.AsEnumerable()。選擇(p ...並且它運行得非常好。 – 2011-03-21 02:18:16

+1

「關於此主題的冗長文章」鏈接似乎已被打破。:-( – 2015-05-22 18:25:42

+0

@BrokednGlass好的答案。謝謝 – User 2015-06-08 09:59:00

34

這裏有一個選擇:

.Select(p -> SqlFunctions.StringConvert((double) 
        SqlFunctions.DatePart("m", p.modified)).Trim() + "/" + 
       // SqlFunctions.DateName("mm", p.modified) + "/" + MS ERROR? 
       SqlFunctions.DateName("dd", p.modified) + "/" + 
       SqlFunctions.DateName("yyyy", p.modified) 

顯然DateName("MM", ..)闡明月份名稱,其中DatePart("mm", ..)提供一個數值,因此StringConvert(),但左墊用空格,因此.Trim()結果。

+1

這很好!我需要這樣做以保持我的原始對象IQueryable。謝謝! – duyn9uyen 2013-07-17 16:23:06

+0

簡單,沒有轉換爲首先是可枚舉的 – brian 2013-10-30 08:24:21

+0

這是一個非常有用的答案。謝謝:-) – 2014-04-04 08:03:29

0

這可能不會增加很多,但萬一任何人都像我一樣瘋狂,這裏是完整的代碼,如果您需要使用DatePart/DateName爲Dr. Zim的答案構建表達式樹,還包括時間部分。顯然,爲了其他目的,您可以更改Product-> YourInitialType,ProductVM-> YourResultType和modified-> YourProperty。

編輯(1/23/08):由此生成的SQL在6.0.2和6.1.3之間更改。最初,如果值爲null,則生成的SQL將創建一個空結果。在這種情況下,我認爲這是可取的,但我可以看到爲什麼在其他情況下它不會被期望(null +「一個字符串值」= null),並且可能導致輸出不等於您希望的值。我將詳細介紹列輸出如何在下面進行更改,但蹭它是現在這將輸出空值「//::」。我只是在我的調用代碼中處理這個輸出作爲特例,並手動將其更改爲null,但其他人可能想要解決添加更強大的結果以確保空值輸出爲空。還值得注意的是,新版本中的SQL語句非常長。

public class UserProductVM { 
    ... 
    private DateTime _modified; 

    public DateTime SetModified { set { _dateEvent = value; } } 
    public string Modified { get { return _modified.ToString("dd MMM yyyy @ HH:mm:ss"); } } 
    ... 
} 

然後你將值賦給SetModified之,改變你這樣的代碼:

ParameterExpression paramExp = Expression.Parameter(typeof(Product)); 
string propertyName = "modified";    
Expression propertyOrField = Expression.PropertyOrField(paramExp, propertyName); 

MethodInfo datePartMethod = typeof(System.Data.Entity.SqlServer.SqlFunctions).GetMethods().Where(x => x.Name == "DatePart" && x.GetParameters().Length == 2 && x.GetParameters()[1].ParameterType == typeof(DateTime?)).First(); 
MethodInfo dateNameMethod = typeof(System.Data.Entity.SqlServer.SqlFunctions).GetMethods().Where(x => x.Name == "DateName" && x.GetParameters().Length == 2 && x.GetParameters()[1].ParameterType == typeof(DateTime?)).First(); 
MethodInfo stringConvertMethod = typeof(System.Data.Entity.SqlServer.SqlFunctions).GetMethods().Where(x => x.Name == "StringConvert" && x.GetParameters().Length == 1 && x.GetParameters()[0].ParameterType == typeof(decimal?)).First(); 
MethodInfo stringConcatMethod = typeof(string).GetMethods().Where(x => x.Name == "Concat" && x.GetParameters().Length == 2 && x.GetParameters()[0].ParameterType == typeof(string) && x.GetParameters()[1].ParameterType == typeof(string)).First(); 
MethodInfo stringTrimMethod = typeof(string).GetMethods().Where(x => x.Name == "Trim" && x.GetParameters().Length == 0).First(); 
Type projectedType = typeof(ProductVM); 
NewExpression newHolder = Expression.New(projectedType); 
MemberInfo member = anonType.GetMember("modified")[0]; 
var monthPartExpression = Expression.Call(null, datePartMethod, Expression.Constant("mm", typeof(string)), propertyOrField); 
var convertedMonthPartExpression = Expression.Call(null, stringConvertMethod, Expression.Convert(monthPartExpression, typeof(decimal?))); 
var convertedDayPartExpression = Expression.Call(null, dateNameMethod, Expression.Constant("dd", typeof(string)), propertyOrField); 
var convertedYearPartExpression = Expression.Call(null, dateNameMethod, Expression.Constant("yyyy", typeof(string)), propertyOrField); 
var convertedHourPartExpression = Expression.Call(null, dateNameMethod, Expression.Constant("hh", typeof(string)), propertyOrField); 
var convertedMinutePartExpression = Expression.Call(null, dateNameMethod, Expression.Constant("n", typeof(string)), propertyOrField); 
var convertedSecondPartExpression = Expression.Call(null, dateNameMethod, Expression.Constant("ss", typeof(string)), propertyOrField); 

var allAddedExpression = Expression.Call(null, stringConcatMethod, 
      convertedMonthPartExpression, 
      Expression.Call(null, stringConcatMethod, 
       Expression.Constant("/", typeof(string)), 
       Expression.Call(null, stringConcatMethod, 
        convertedDayPartExpression, 
        Expression.Call(null, stringConcatMethod, 
         Expression.Constant("/", typeof(string)), 
         Expression.Call(null, stringConcatMethod, 
          convertedYearPartExpression, 
          Expression.Call(null, stringConcatMethod, 
           Expression.Constant(" ", typeof(string)), 
           Expression.Call(null, stringConcatMethod, 
            convertedHourPartExpression, 
            Expression.Call(null, stringConcatMethod, 
             Expression.Constant(":", typeof(string)), 
             Expression.Call(null, stringConcatMethod, 
              convertedMinutePartExpression, 
              Expression.Call(null, stringConcatMethod, 
               Expression.Constant(":", typeof(string)), 
               convertedSecondPartExpression 

)))))))))); 
var trimmedExpression = Expression.Call(allAddedExpression, stringTrimMethod, new Expression[] { });  
var month = Expression.Bind(member, trimmedExpression); 

MemberInitExpression memberInitExpression = 
    Expression.MemberInit(
     newHolder, 
     new MemberBinding[] { month }); 
var lambda = Expression.Lambda<Func<Product, ProductVM>>(memberInitExpression, paramExp); 
0

這種結構(我假設的數據類型爲DATETIME)創建一個新的POCO

from a in Products 
select new UserProductVM 
{ 
    ... 
    SetModified = a.modified 
} 

,請注意我使用UserProductVM代替ProductVMSetModified改爲修改

然後,當你得到修改屬性,新的POCO是要去把它作爲你格式化字符串。

相關問題