我有一个简单的实体

public class MyEntity
{
    public DateTime Date { get; set; }

    public string Code { get; set; }

    public decimal Value { get; set; }
}


我用EF将其存储到SQL数据库,一切都很好。此处显示数据样本。某个代码可以包含给定日期的数据,而不能包含其他日期的数据。

| Date       |  Code  | Value  |
+------------+--------+--------+
| 2016-10-01 |   AA   | .5     |
| 2016-10-02 |   AA   | .6     |
| 2016-10-03 |   AA   | .7     |
| 2016-09-30 |   BB   | .51    |
| 2016-10-02 |   BB   | .64    |
| 2016-10-04 |   BB   | .75    |
| 2016-09-30 |   CC   | .51    |


现在我想知道,什么是检索数据的最佳方法,这样我就可以得到包含给定范围内所有日期的结果?这样看起来像这样:

| 2016-10-02 |   AA   | .6     |
| 2016-10-03 |   AA   | .7     |
| 2016-10-04 |   AA   | .7     | <<-- this is same as day before
| 2016-10-02 |   BB   | .64    |
| 2016-10-03 |   BB   | .64    | <<-- this is same as day before
| 2016-10-04 |   BB   | .75    |
| 2016-10-02 |   CC   | .51    | <<-- this is latest available value
| 2016-10-03 |   CC   | .51    |
| 2016-10-04 |   CC   | .51    |


基本上,规则是,如果一天中缺少数据,那么我会选择该日期之前的第一天。

该查询请求给定日期范围内的数据,并假定数据库中至少有一个用于上一个日期的实体,因此无论查询如何,我总可以有一个最新可用值的值。

我可以通过几个LINQ查询和一些代码来获取此信息,但是我想知道是否可以采用一种好的方法甚至SQL语法可以提供帮助?

到目前为止,我正在使用以下查询和方法循环显示范围内的日期

public void CreateReportForDates()
{
   var dates = new [] { DateTime.Today, DateTime.Today.AddDay(-1) } ;
   var values = this.GetDataByDateRange(dates);

   .... do something with these values ....

}

public ICollection<MyEntity> GetDataByDate(EntityContext dbContext, DateTime date)
{
    var queryInDay = from element in dbContext.MyEntities
                     where element.Date <= date
                     group element by element.Code
                     into groupedElements
                     select groupedElements.OrderBy(x => x.Date).First();

    return queryInDay.ToList();
}

public IEnumerable<MyEntity> GetDataByDateRange(IEnumerable<DateTime> dates)
{
     foreach(var date in dates)
     {
         var dbContext = new EntityContext();

         foreach(var result in this.GetDataByDate(dbContext, date)
         {
            result.Date = date;
            yield return result;
         }

         dbContext.Dispose();
     }
}

最佳答案

我不能说是否可以使用纯LINQ to Entities查询,但是即使这样,效率也很低。

我仍将使用混合方法,即通过单个查询仅从数据库中获取必要的数据,然后将结果扩展到内存中。对于扩展,我将按{Code, Date}(在数据库内部)对记录进行排序,然后使用高效的迭代(非LINQ)方法:

public IEnumerable<MyEntity> GetDataByDateRange(DateTime startDate, DateTime endDate)
{
    var dbContext = new EntityContext();
    var dbQuery =
        from g in (from e in dbContext.MyEntities
                   where e.Date <= startDate
                   group e.Date by e.Code into g
                   select new { Code = g.Key, MaxDate = g.Max() })
        join e in dbContext.MyEntities on g.Code equals e.Code
        where e.Date >= g.MaxDate && e.Date <= endDate
        orderby e.Code, e.Date
        select e;

    using (var result = dbQuery.GetEnumerator())
    {
        for (bool more = result.MoveNext(); more;)
        {
            MyEntity next = result.Current, item = null;
            for (var date = startDate; date <= endDate; date = date.AddDays(1))
            {
                if (item == null || (next != null && next.Date == date))
                {
                    item = next;
                    more = result.MoveNext();
                    next = more && result.Current.Code == item.Code ? result.Current : null;
                }
                else if (item.Date != date)
                    item = new MyEntity { Date = date, Code = item.Code, Value = item.Value };
                yield return item;
            }
        }
    }
}

关于c# - 在 Entity Framework 中按日期对实体进行划分,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39979731/

10-17 01:19