在LINQ-to-entities查询中将日期时间转换为格式化字符串

32

如何将DateTime转换为格式化的字符串?

需要帮助的是以下查询中的这一行:

StartDate = string.Format("{0:dd.MM.yy}", p.StartDate)

整个查询:

var offer = (from p in dc.CustomerOffer
             join q in dc.OffersInBranch
             on p.ID equals q.OfferID
             where q.BranchID == singleLoc.LocationID
             let value = (p.OriginalPrice - p.NewPrice) * 100 / p.OriginalPrice
             orderby value descending
             select new Offer()
             {
                 Title = p.OfferTitle,
                 Description = p.Description,
                 BestOffer = value,
                 ID = p.ID,
                 LocationID = q.BranchID,
                 LocationName = q.CustomerBranch.BranchName,
                 OriginalPrice = SqlFunctions.StringConvert((decimal)p.OriginalPrice),
                 NewPrice = SqlFunctions.StringConvert((decimal)p.NewPrice),
                 StartDate = string.Format("{0:dd.MM.yy}", p.StartDate)
             }).First();

我遇到了以下错误消息:

LINQ to Entities 不认识方法 'System.String ToString(System.String)',且此方法无法被转换为存储表达式。

7个回答

38

另一种选项是使用SqlFunctions.DateName,您的代码将像这样:

var offer = (from p in dc.CustomerOffer
                 join q in dc.OffersInBranch
                     on p.ID equals q.OfferID
                 where q.BranchID == singleLoc.LocationID
                 let value = (p.OriginalPrice - p.NewPrice) * 100 / p.OriginalPrice
                 orderby value descending
                 select new
                 {
                     Title = p.OfferTitle,
                     Description = p.Description,
                     BestOffer = value,
                     ID = p.ID,
                     LocationID = q.BranchID,
                     LocationName = q.CustomerBranch.BranchName,
                     OriginalPrice = SqlFunctions.StringConvert((decimal)p.OriginalPrice),
                     NewPrice = SqlFunctions.StringConvert((decimal)p.NewPrice),
                     StartDate = SqlFunctions.DateName("day", p.StartDate) + "/" + SqlFunctions.DateName("month", p.StartDate) + "/" +  SqlFunctions.DateName("year", p.StartDate)
                 })

如果你不想添加额外的选择新块,我发现这很有用。


我必须添加以下内容:using System.Data.Objects.SqlClient; 才能使用 SqlFunctions - Kristopher
1
如果您之前没有添加 System.Data.Entity.dll 的引用,请添加它以使用 sqlfunctions。 - Ram
您还可以使用 SqlFunctions.DatePart 来处理特定格式。 - Sumit Roy

21

编辑:现在我理解了问题,我再试一次 :)

var offer = (from p in dc.CustomerOffer
                     join q in dc.OffersInBranch
                         on p.ID equals q.OfferID
                     where q.BranchID == singleLoc.LocationID
                     let value = (p.OriginalPrice - p.NewPrice) * 100 / p.OriginalPrice
                     orderby value descending
                     select new
                     {
                         Title = p.OfferTitle,
                         Description = p.Description,
                         BestOffer=value,
                         ID=p.ID,
                         LocationID=q.BranchID,
                         LocationName=q.CustomerBranch.BranchName,
                         OriginalPrice=SqlFunctions.StringConvert((decimal)p.OriginalPrice),
                         NewPrice=SqlFunctions.StringConvert((decimal)p.NewPrice),
                         StartDate=p.StartDate

                     })
                     .ToList()
                     .Select(x => new Offer()
                     {
                         Title = x.OfferTitle,
                         Description = x.Description,
                         BestOffer=value,
                         ID=x.ID,
                         LocationID=x.BranchID,
                         LocationName=x.CustomerBranch.BranchName,
                         OriginalPrice=x.OriginalPrice,
                         NewPrice=x.NewPrice,
                         StartDate=x.StartDate.ToString("dd.MM.yy")
                     }).First();

我知道有点长,但这就是 Linq To SQL 的问题所在。

当你使用 Linq 时,数据库调用直到你使用像 ToList() 或 First() 这样的方法才会被执行,产生实际的对象。一旦第一个 .First() 调用执行了 SQL 调用,你现在正在使用 .NET 类型,并且可以使用 DateTime 相关的方法。


2
错误:LINQ to Entities 不认识方法 'System.String ToString(System.String)',并且该方法无法转换为存储表达式。 - Reza.Hoque
那么p.StartDate是DateTime还是字符串? - mccow002
LINQ无法将日期时间转换为字符串。关于此问题有很多论坛帖子。请参见此链接https://dev59.com/M1nUa4cB1Zd3GeqPdsff。但我不确定如何使其正常工作。 - Reza.Hoque
让我们在聊天中继续这个讨论:http://chat.stackoverflow.com/rooms/4700/discussion-between-kandroid-and-mccow002 - Reza.Hoque
2
你应该将第一个 First() 替换为 Take(1),以便在后续的 Select 中获得 IEnumerable。或者干脆将其省略。 - Gert Arnold

4
我最终使用了sql函数FORMAT,以下是这个实现的简化版本:

https://weblogs.asp.net/ricardoperes/registering-sql-server-built-in-functions-to-entity-framework-code-first

首先,您需要在EF中定义该函数:
public class FormatFunctionConvention : IStoreModelConvention<EdmModel>
{
    public void Apply(EdmModel item, DbModel model)
    {
        var payload = new EdmFunctionPayload
        {
            StoreFunctionName = "FORMAT",
            Parameters = new[] {
                FunctionParameter.Create("value", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.DateTime), ParameterMode.In),
                FunctionParameter.Create("format", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String), ParameterMode.In)
            },
            ReturnParameters = new[] {
                FunctionParameter.Create("result", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String), ParameterMode.ReturnValue)
            },
            Schema = "dbo",
            IsBuiltIn = true
        };

        item.AddItem(EdmFunction.Create("FORMAT", "CodeFirstDatabaseSchema", item.DataSpace, payload, null));
    }
}

然后将其定义为C#方法:
public static class SqlFunctions
{
    [DbFunction("CodeFirstDatabaseSchema", "FORMAT")]
    public static String Format(this DateTime value, string format)
    {
        return value.ToString(format);
    }

    [DbFunction("CodeFirstDatabaseSchema", "FORMAT")]
    public static String Format(this DateTime? value, string format)
    {
        return value?.ToString(format);
    }
}

在你的DbContext中注册它:

public class SqlDb : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Conventions.Add(new FormatFunctionConvention());
    }
}

最后,你可以这样调用它:
var x = db.MyItems.Select(i => new { FormattedDate = SqlFunctions.Format(i.MyDate, "MM/dd/yyyy") }).ToArray();

0
我发现在处理数字或日期时间对象的字符串格式时,最简单和高效的方法是使用字符串插值。它将在 SQL 查询中返回实际的 DateTime/int/float/double 等对象,然后在客户端进行投影时进行字符串格式化。我修改了您下面的查询,请注意 OriginalPrice、NewPrice 和 StartDate 的转换:
var offer = (from p in dc.CustomerOffer
         join q in dc.OffersInBranch
         on p.ID equals q.OfferID
         where q.BranchID == singleLoc.LocationID
         let value = (p.OriginalPrice - p.NewPrice) * 100 / p.OriginalPrice
         orderby value descending
         select new Offer()
         {
             Title = p.OfferTitle,
             Description = p.Description,
             BestOffer = value,
             ID = p.ID,
             LocationID = q.BranchID,
             LocationName = q.CustomerBranch.BranchName,
             OriginalPrice = $"{p.OriginalPrice:C2}",
             NewPrice = $"{p.NewPrice:C2}",
             StartDate = $"{p.StartDate:dd.MM.yy}"
         }).First();

0
在 vb(也适用于 c# 改变语法)中:
Imports System.Data.Entity
... 
query.Select(Function(x) New MyObject With {
    ...
    .DateString = DbFunctions.Right("00" & x.DateField.Day, 2) & "/" & DbFunctions.Right("00" & x.DateField.Month, 2) & "/" & x.DateField.Year
    ...
}).ToList()

注意:ToList()、ToEnumerable() 不是正确的方法,因为它们会执行查询,用户需要使用 Linq to SQL。

0

这就是我们所做的,我们向类中添加了一个新函数,并在查询中像往常一样查询日期:

[ComplexType]
public class Offer
{    
    public DateTime StartDate 
    {
        get;
        set;
    }

   public String Title
   {
       get;
       set;
   }

   /*Other fields*/      
   .
   .
   .


    public string FormattedDate(string format)
    {
        return Date.ToString(format);
    }
}



var offer = (from p in dc.CustomerOffer
         join q in dc.OffersInBranch
         on p.ID equals q.OfferID
         where q.BranchID == singleLoc.LocationID
         let value = (p.OriginalPrice - p.NewPrice) * 100 / p.OriginalPrice
         orderby value descending
         select new Offer()
         {
             Title = p.OfferTitle,
             Description = p.Description,
             BestOffer = value,
             ID = p.ID,
             LocationID = q.BranchID,
             LocationName = q.CustomerBranch.BranchName,
             OriginalPrice = SqlFunctions.StringConvert((decimal)p.OriginalPrice),
             NewPrice = SqlFunctions.StringConvert((decimal)p.NewPrice),
             StartDate = p.StartDate
         }).First();

然后,您只需调用FormattedDate字段并传递所需的格式即可。

edit1.Text = offer.FormattedDate("dd.MM.yy");

或者可以只定义一个带有getter的字段:
    public string FormattedDate
                {
                   get { return Date.ToString("dd.MM.yy") };
                }

 edit1.Text = offer.FormattedDate;

如果你的类是一个实体,你需要声明该类的新部分并添加字段。

希望这能帮助到某些人。


-1
如果你需要一个日期时间,你需要使用 .ToShortDateString()。但是你还需要声明它为 AsEnumerable()。
var offer = (from p in dc.CustomerOffer.AsEnumerable()
                 join q in dc.OffersInBranch
                     on p.ID equals q.OfferID
                 where q.BranchID == singleLoc.LocationID
                 let value = (p.OriginalPrice - p.NewPrice) * 100 / p.OriginalPrice
                 orderby value descending
                 select new
                 {
                     Title = p.OfferTitle,
                     Description = p.Description,
                     BestOffer=value,
                     ID=p.ID,
                     LocationID=q.BranchID,
                     LocationName=q.CustomerBranch.BranchName,
                     OriginalPrice=SqlFunctions.StringConvert((decimal)p.OriginalPrice),
                     NewPrice=SqlFunctions.StringConvert((decimal)p.NewPrice),
                     StartDate=p.StartDate

                 })
                 .ToList()
                 .Select(x => new Offer()
                 {
                     Title = x.OfferTitle,
                     Description = x.Description,
                     BestOffer=value,
                     ID=x.ID,
                     LocationID=x.BranchID,
                     LocationName=x.CustomerBranch.BranchName,
                     OriginalPrice=x.OriginalPrice,
                     NewPrice=x.NewPrice,
                     StartDate=x.StartDate.ToShortDateString()
                 }).First();

不行。如果我们只使用IQueryable,ToShortDateString将无法工作。 - user8599026

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接