实体框架,获取所选项

时间:2017-01-10 09:56:26

标签: c# entity-framework

我想从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
像这样。

谢谢。

5 个答案:

答案 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的序列,其中

  • result 1 =来自源序列的元素,Id = someId。这是序列的中间元素。
  • result [0] =来自具有最大日期&lt;的最大源序列的元素。结果1。日期。
  • result [2] =来自具有最小数据的源序列的元素&gt;结果1。日期

从您的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();