我想从db获取一个项目,以及它之前和之后的项目。
var data= repo .OrderBy(a => a.Date)
.Select((item, index) => new { item, index })
.Where(itemAndIndex=>itemAndIndex.item.Id == someId)
这是我到目前为止所得到的。
澄清,
让我们说这是我的表
Id Name Date
1 SomeText1 01.01.2017
2 SomeText2 03.01.2017
3 SomeText3 02.01.2017
4 SomeText4 04.01.2017
5 SomeText5 05.01.2017
我想对Id==3
执行选择查询,然后按日期字段对结果进行排序,并获取项目列表
Id Name Date
1 SomeText1 01.01.2017
3 SomeText3 02.01.2017
2 SomeText2 03.01.2017
像这样。
谢谢。
答案 0 :(得分:1)
这与Harald Coppoolse's answer中的想法相同(我认为这是满足您需求的唯一合理方式),但最佳(IMO)LINQ to Entities SQL查询转换(假设repo
是代表你的桌子的IQueryable<T>
:
var data = repo
.Where(elem => elem.Id == someId)
.SelectMany(elem =>
repo.Where(e => e.Date < elem.Date).OrderByDescending(e => e.Date).Take(1)
.Concat(new[] { elem })
.Concat(repo.Where(e => e.Date > elem.Date).OrderBy(e => e.Date).Take(1)))
.ToList();
答案 1 :(得分:0)
最简单的方法:
var data = repo.OrderBy(x => x.Date)
.Select((item, index) => new { item, index });
var idx = data.First(x => x.item.Id == someId);
var result = data
.Where(x => x.index >= idx.index)
.Take(3);
答案 2 :(得分:0)
这不适用于EF
,但也会稍作修改:
public class Data
{
public int id;
public string name;
public DateTime date;
}
class Program
{
static void Main(string[] args)
{
List<Data> l = new List<Data>
{
new Data { id = 1, name = "Name1", date = DateTime.Parse("2017/01/01")},
new Data { id = 2, name = "Name2", date = DateTime.Parse("2017/01/03")},
new Data { id = 3, name = "Name3", date = DateTime.Parse("2017/01/02")},
new Data { id = 4, name = "Name4", date = DateTime.Parse("2017/01/04")},
new Data { id = 5, name = "Name5", date = DateTime.Parse("2017/01/05")},
};
int id = 2;
var result = l.Where(c => c.id == id)
.Union(l.Where(c => c.date < l.Where(t => t.id == id).Select(d => d.date).First()).OrderByDescending(c => c.date).Take(1))
.Union(l.Where(c => c.date > l.Where(t => t.id == id).Select(d => d.date).First()).OrderBy(c => c.date).Take(1)).ToList();
}
}
答案 3 :(得分:0)
另一种最简单的方法:
var data= repo.OrderBy(c => c.Date)
.Where(c => c.Id == id || c.Id == id - 1 || c.Id == id + 1)
.Select(c => new { c.Id, c.Name,c.Date });
答案 4 :(得分:0)
如果您的带有someId的商品是您的有序列表中的第一个或最后一个商品,则您忘记提及应该填写的内容,在这种情况下您没有上一个或下一个商品。
如果没有someId的项目,你想要什么?空序列或具有三个NULL值的序列?
此外,您的日期值是否独一无二?如果你有几个具有相同日期的项目,你想要什么作为上一个项目和下一个项目?
除了从RepoElements的源序列中查看您的问题之外,您还要选择3个RepoElements的序列,其中
从您的repo序列中,使用Where选择结果1。之后使用Select with Min和Max来查找result [0]和result [2]并将所有三个结果放在一个数组中。最后使用SingleOrDefault选择具有正确结果的唯一元素1:
var result = repo
.Where(repoElement => repoElement.Id == someId)
.Select( result1 => new RepoElement[]
{
// [0]: the largest element with date < date of item with Id == someId
repo.Where(repoElement => repoElement.Date < result1.Date)
.Max(repoElement => repoElement.Date),
// [1] the item with Id == someId
result1,
// [2] the smallest element date > date of item with Id == someId
repo.Where(repoElement => repoElement.Date > result1.Date)
.Min(repoElement => repoElement.Date),
})
.SingleOrDefault();
第一个使用索引完成的地方:快速。 Select需要两个遍历:一个用于查找小于中间元素的最大元素,另一个用于查找大于中间元素的最小元素。我认为在大多数情况下,这将比排序更快
请注意,如果没有更小/更大日期的元素,那么Max的结果将是默认值,在您的情况下为NULL
如果您的日期不是唯一的,您将找到最大的c.q.没有日期的最小值。
<强>加成强>
我刚刚意识到我使用的函数Max不返回具有Max值的元素,而是返回Maximum值本身。幸运的是,MSDN Enumerable.Max描述了Max使用IComparable的功能。
考虑让你的类实现IComparable,它将按日期排名。
private class RepoElement: IComparable<MyData>
{
public int Id {get; set;}
public string Name {get; set;}
public DateTime Date {get; set;}
public int CompareTo(RepoElement other)
{ // this object smaller than other object
// if this date smaller than other date
return this.Date.CompareTo(other.Date);
}
}
var result = repo
.Where(repoElement => repoElement.Id == someId)
.Select( result1 => new RepoElement[]
{
repo.Where(repoElement => repoElement.Date < result1.Date).Max(),
repoElement,
repo.Where(repoElement => repoElement.Date > result1.Date).Min(),
}
这将使用扩展函数Enumerable.Max(),它返回一个TSource。
虽然这样可行,但这种方法的缺点是它只适用于IEnumerable,而不适用于IQueryable。它无法在数据库端执行。
如果您的集合非常大,并且您确实需要将其作为IQueryable(在数据库端)执行,请考虑使用Enumerable.Aggregate来查找元素[0]和[2]。
Aggregate比较序列的两个第一个元素,决定哪一个是“最佳”,并使用这个“最佳”元素与第三个项目进行比较,以再次确定哪一个是“最佳”并使用这个与第四项等进行比较。最后它返回“最佳”。
var result = repo
.Where(repoElement => repoElement.Id == someId)
.Select(repoElement => new RepoElement[]
{
// [0]: take only the elements that are smaller,
// aggregate to find the largest one:
repo.Where(element => element.Date < repoElement.Date)
.Aggregate(
// compare the largest item already found, with the current one
// and take the largest one as largest
(largest, next) => next.Date > largest.Date ? next : largest),
// [1]
repoElement,
// [2]: take only the elements that are bigger
// aggregate to find the smallest one
repo.Where(element => element.Date > repoElement.Date)
.Aggregate(
// compare the smallest item already found, with the current one
// and take the smallest one as smallest
(smallest, next) => next.Date < smallest.Date ? next : smallest),
})
.SingleOrDefault();