可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I know that LINQ to SQL does not convert DateTime
to string
since there is no ToString()
in SQL.
But how can I convert the DateTime
into a formatted string?
This is the line in the following query that needs help:
StartDate = string.Format("{0:dd.MM.yy}", p.StartDate)
The whole query:
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();
I get the following error message:
LINQ to Entities does not recognize the method 'System.String ToString(System.String)' method, and this method cannot be translated into a store expression.
回答1:
EDIT: Now that I understand the question, I'm giving it another shot :)
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();
I know it's a bit long, but that's the problem with Linq To SQL.
When you use linq, the database call isn't executed until you use something such as ToList() or First() that results in actual objects. Once that SQL call is executed by the first .First() call, you're now working with .NET types, and can use DateTime stuff.
回答2:
Another option is using SqlFunctions.DateName , your code will be like this:
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)
})
I found it useful if you don't want to add an extra select new block.
回答3:
if it's a datetime you need to use the .ToShortDateString()
. But you also need to declare it 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();
回答4:
That is what we did, we added a new function to the class and we query the date as normal in the query:
[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();
Then you can just call the FormattedDate field passing the desired format.
edit1.Text = offer.FormattedDate("dd.MM.yy");
Or can can define it as a field with just the getter:
public string FormattedDate
{
get { return Date.ToString("dd.MM.yy") };
}
edit1.Text = offer.FormattedDate;
In case you class is an Entity, you need to declare a new partial of that class and add the field.
Hope this help someone.
回答5:
I ended up using the sql function FORMAT
; here's a simplified version of this implementation:
https://weblogs.asp.net/ricardoperes/registering-sql-server-built-in-functions-to-entity-framework-code-first
First you need to define the function in 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));
}
}
Then define it as C# methods:
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);
}
}
Register it in your DbContext
:
public class SqlDb : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Add(new FormatFunctionConvention());
}
}
And finally, you can call it like so:
var x = db.MyItems.Select(i => new { FormattedDate = SqlFunctions.Format(i.MyDate, "MM/dd/yyyy") }).ToArray();