【问题标题】:Convert datetime to a formatted string inside a LINQ-to-entities query将日期时间转换为 LINQ-to-entities 查询中的格式化字符串
【发布时间】:2011-12-21 10:27:20
【问题描述】:

如何将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)”方法,并且该方法无法转换为存储表达式。

【问题讨论】:

    标签: entity-framework linq


    【解决方案1】:

    另一种选择是使用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
    • 添加对 System.Data.Entity.dll 的引用,如果您之前尝试使用 sqlfunctions
    • 您也可以使用 SqlFunctions.DatePart 获取特定格式
    【解决方案2】:

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

    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() 之类的方法来生成实际对象。一旦该 SQL 调用由第一个 .First() 调用执行,您现在就可以使用 .NET 类型,并且可以使用 DateTime 内容。

    【讨论】:

    • 错误:LINQ to Entities 无法识别方法 'System.String ToString(System.String)' 方法,并且该方法无法转换为存储表达式。
    • p.StartDate 是 DateTime 还是字符串?
    • 是的。 LINQ 无法将日期时间转换为字符串。有很多关于这个的论坛帖子。看到这个stackoverflow.com/questions/6887776/…。但我不知道如何让它工作。
    • 你应该替换第一个First(),呃,例如Take(1) 为后续的 Select 获取 IEnumerable。或者把它排除在外。
    【解决方案3】:

    我最终使用了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();
    

    【讨论】:

      【解决方案4】:

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

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

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

      希望这对某人有所帮助。

      【讨论】:

        【解决方案5】:

        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..

        【讨论】:

          【解决方案6】:

          如果是日期时间,您需要使用.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 将不起作用。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-05-17
          • 1970-01-01
          • 1970-01-01
          • 2013-02-28
          • 2011-11-16
          • 2014-10-29
          相关资源
          最近更新 更多