实体框架4 / Linq:如何在查询中将DateTime转换为字符串?

时间:2011-03-20 18:11:58

标签: entity-framework-4 linq-to-entities tostring

我有以下查询:

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.

Products表中的modified是DateTime。 ProductVM类中的modified是字符串。

有什么想法吗?这必须是一个微不足道的问题。

4 个答案:

答案 0 :(得分:42)

这是另一种选择:

.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 :(得分:20)

Linq to Entities不支持

ToString() - 作为SqlFunctions的一部分,有一个函数助手列表,但这不支持日期到字符串转换。

最简单的方法是首先在查询中投射到匿名类型,然后使用AsEnumerable()投射到IEnumerable - 之后您可以使用ToString(),因为您现在正在使用Linq查询表达式的其余部分的对象(关于此主题here有一篇冗长的文章)。

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

答案 2 :(得分:0)

这可能不会增加很多,但万一有人像我一样疯狂,如果你需要使用DatePart / DateName(包括时间部分)为Zim博士的答案构建表达式树,这里是完整的代码。显然,出于其他目的,您可以更改Product-> YourInitialType,ProductVM-> YourResultType和modified-> YourProperty。

编辑(1/23/08):由此生成的SQL在6.0.2和6.1.3之间发生了变化。最初,如果值为null,则生成的SQL将创建null结果。在这种情况下我认为这是可取的,但我可以看到为什么在其他情况下不需要它(null +“一个字符串值”= null)并且可能导致输出不等于你想要的输出。我将详细说明列输出如何在下面改变,但它的缺点是现在将输出“// ::”表示空值。我只是在我的调用代码中处理此输出作为特殊情况并手动将其更改回null,但其他人可能希望解决添加更强大的结果以确保将null输出为null。值得注意的是,新版本中的SQL语句很长。

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

答案 3 :(得分:0)

使用这种结构创建一个新的POCO(我假设数据类型是DateTime):

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,更改代码如下:

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

请注意我使用 UserProductVM 而不是 ProductVM SetModified 而不是修改

然后,当您获得属性 已修改 时,新POCO会将其作为您格式化的字符串。