将日期时间转换为 LINQ-to-entities 查询中的格式化字符串
Posted
技术标签:
【中文标题】将日期时间转换为 LINQ-to-entities 查询中的格式化字符串【英文标题】:Convert datetime to a formatted string inside a LINQ-to-entities query 【发布时间】: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)”方法,并且该方法无法转换为存储表达式。
【问题讨论】:
【参考方案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 无法将日期时间转换为字符串。有很多关于这个的论坛帖子。看到这个***.com/questions/6887776/…。但我不知道如何让它工作。 让我们continue this discussion in chat 你应该替换第一个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 将不起作用。以上是关于将日期时间转换为 LINQ-to-entities 查询中的格式化字符串的主要内容,如果未能解决你的问题,请参考以下文章