EF CORE中的LINQ等效于DbFunctions.TruncateTime是什么?

58

我在我的 .net 应用程序中有以下正常工作的LINQ

    public ActionResult Index()
    {
        Dictionary<DateTime?, List<Event>> result;
        result = (from events in db.Events.Include("Activity")
                      where events.IsActive
                      group events by DbFunctions.TruncateTime(events.DateTimeFrom) into dateGroup
                      select new { EventDate = dateGroup.Key, Events = dateGroup.ToList() }).ToDictionary(x => x.EventDate, x => x.Events);

        return View(result);
    }

当我在EF Core中使用时,我无法使用DbFunctions。 我该如何重写代码以使它在Microsoft.EntityFrameworkCore中正常工作?如果有差异,我正在使用SQLite。


2
在 .Net Core 3+ 中,您可以使用 EF.Functions。 - Avjol Sakaj
7个回答

95
在EF6中,使用DbFunctions.TruncateTime代替DateTime.Date属性,因为后者由于某种原因不受支持。在EF Core中,前者不再需要,因为DateTime.Date现在被正确识别和翻译。
group events by events.DateTimeFrom.Date into dateGroup

很遗憾目前没有文档说明支持哪些内容,所以通常的做法是尝试使用对应的CLR方法/属性(如果有的话),并检查它是否能够转换成SQL,以及如何转换。


9
要在ASP.NET CORE中使用DbFunctions,您必须创建一个对象。
var DbF = Microsoft.EntityFrameworkCore.EF.Functions;

现在你可以轻松地使用它。
var now = DateTime.Now;

int count = db.Tbl.Count(w => DbF.DateDiffDay(now, w.RegisterDate) <= 3);

更多细节请参考github


2
将一个对象分配给变量如何导致它具有不同的方法或更改其在C#中的可访问性? - Reinis
@Reinis 在运行时,这个对象会被 QueryCompiler 转换成 SQL 代码。 - M.R.T
1
但是为什么需要赋值呢?将EF.Functions对象分配给一个变量,如何改变TruncateTime方法是否可访问?为什么不直接使用该对象而不将其分配给变量? - Reinis
@Reinis,那是因为我的代码更加清晰。你也可以直接使用EF.Functions.DateDiffDay() - M.R.T

4

目前EF Core还不支持DbFunctions。但是您可以使用"原生SQL查询"。

您可以在这里找到"原生SQL查询"的文档。

同时,您可以在这里跟踪EF Core的DbFunctions问题。


4
+100 如果提供跟踪链接!现在我看到.NET Core 2.0有EF.Functions。 - Andrzej Martyna

4

EF Core 3.0

我终于找到了一个可行的答案。问题是我想在数据库中对DateTime列进行日期分组。

关键是要使用EF.Property函数。这允许类具有DateTime属性,用于添加该级别的数据,但是下面的代码使我可以重新定义它为日期。 然而…我怀疑如果我在类上声明了该属性,它可能已经允许我使用.Date函数,但它当时没有让我这样做。

所以解决方案可能是在模型上定义属性,或使用以下内容在查询中定义它。

EF.Property(s,"dt").Date

完整代码

var myData = _context.ActivityItems
                            .GroupBy(a => new { nlid = a.lid, nsd = EF.Property<DateTime>(a, "dt").Date })
                            .Select(g => new
                            {
                                g.Key.nlid,
                                g.Key.nsd,
                                cnt = g.Count()
                            });

太棒了。在我的情况下,这有助于使用npgsql在DateTimeOffset属性上应用DATE_TRUNC。 - bvj

3

在我的情况下,它是以这种方式工作的,而不是使用DbFunctions.TruncateTime或EntityFunctions.TruncateTime-

result = _context.ActivityItems.Where(a =>  a.DateTimeFrom.Value.Date == paramFilter.DateTimeFrom.Value.Date);

它首先在服务器端将日期转换为 WHERE 条件,然后与参数日期值进行比较。

WHERE CONVERT(date, [a].[DateTimeFrom]) = @__paramFilter_DateTimeFrom_Value_Date_0

0

0

我还将其重写为Lambda,并使其异步化。看起来工作方式相同。

var temp = await _context.Events.Where(x => x.IsActive)
            .Include(a => a.Activity)
            .GroupBy(x => x.DateTimeFrom.Date)
            .Select(g => new { EventDate = g.Key, Events = g.ToList() }).ToDictionaryAsync(x => x.EventDate, x => x.Events);

所以你使用了 DateTime 对象的 .Date 属性,并且在 EF Core 中起作用了? - Chaim Eliyah

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