我有一个简单的实体
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();
}
}
答案 0 :(得分:1)
我不能说纯粹的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;
}
}
}
}