这是选择上一条和下一条记录的正确方法吗?给定当前记录的ID

本文关键字:一条 记录 ID 方法 选择 | 更新日期: 2023-09-27 18:26:34

我需要运行一个LINQ查询,它将返回3行(当前记录、上一条记录和相对于当前记录的下一条记录。ProductID是我自动生成的标识列。

目前,我正在使用Union LINQ声明来完成这项任务,但我不确定是否有更好或更有效的方法来完成同样的任务。

我得到的是:

var ProductID = 10;
var Results = (from p in DB.Products
where p.ProductID == ProductID - 1 //Previous record.
select new Product
{
    ProductID = p.ProductID,
    ProductTitle = p.ProductTitle,
    Views = p.Views,
}).Union(from p in DB.Products
where p.ProductID == ProductID //Current record
select new Product
{
    ProductID = p.ProductID,
    ProductTitle = p.ProductTitle,
    Views = p.Views,
}).Union(from p in DB.Products
where p.ProductID == ProductID + 1 //Next record.
select new Product
{
    ProductID = p.ProductID,
    ProductTitle = p.ProductTitle,
    Views = p.Views,
});

这应该为ProductID 9、ProductID 10和ProductID 11返回3行。谢谢

这是选择上一条和下一条记录的正确方法吗?给定当前记录的ID

就我个人而言,我会使用这种方法:它的好处是在范围内缺少Id的地方工作。一个勇敢的人认为所有的ID都已被记录并存在。

 var currAndNext = Context.Set<TPoco>()
                  .Where<TPoco>(t=>t.id == id)
                  .OrderBy(t=>t.id)
                  .Skip(0)
                  .Take(2);
 var prev = Context.Set<TPoco>()
                  .Where<TPoco>(t=>t.id == id)
                  .OrderByDescending(t=>t.id)
                  .Skip(1)
                  .Take(1);

您的方法可以很快重写如下:

var ProductID = 10;
var Results = (from p in DB.Products
where p.ProductID >= ProductID - 1 &&
      p.ProductID <= ProductID + 1
select new Product
{
   ProductID = p.ProductID,
   ProductTitle = p.ProductTitle,
   Views = p.Views,
});

但请注意,只有在没有从Products表中删除与指定productID对应的记录的情况下,才会返回所需的内容。

GwynBleidd提出了一个很好的解决方案,但是您也可以指定一个ID列表,在您的情况下如下:

var ids = new[] {ProductID - 1, ProcuctID, ProductID + 1};

并在where子句中使用它

var Results = from p in DB.Products
              where ids.Contains(p.ProductID)
              select new Product
              {
                 ProductID = p.ProductID,
                 ProductTitle = p.ProductTitle,
                 Views = p.Views,
              };

我认为这更通用,EF会将其转换为WHERE [ProductID] IN (...),查询执行计划器可以很好地处理它。

以下是我解决问题的方法——避免使用+1,-1。

在我的案例中,我试图显示上一篇/下一篇发布的博客文章。如果下一篇/上一篇博客文章未发布,则+1、-1将不起作用。更不用说Ids不总是连续的可能性了。

在您的情况下,您可能不想展示缺货的产品。

var products = db.Products.Where(x => x.Quantity > 0).OrderBy(x => x.ProductId).ToList();
var previous = products.LastOrDefault(x => x.ProductId < id),
var next = products.FirstOrDefault(x => x.ProductId > id)

这将返回上一个和下一个产品,其中ProductId最接近您的起始id

注意:如果您的列表已按顺序排列,则不需要.OrderBy(x => x.ProductId)

以下是我对此的看法:

await using var context = new CsuContext(this._csuContextOptions);
var offenseLogs =
  context.OffenseLogs ?? throw new Exception("SQL Connection Error");
var last = await offenseLogs.OrderByDescending(log => log.Id)
                            .FirstOrDefaultAsync()
                            .ConfigureAwait(false);
if (id == 0) id = last.Id;
var currentAndNext = offenseLogs.Where(log => log.Id >= id)
                                .OrderBy(log => log.Id)
                                .Take(2);
var current = await currentAndNext.FirstOrDefaultAsync()
                                  .ConfigureAwait(false);
var next = await currentAndNext.Skip(1)
                               .FirstOrDefaultAsync()
                               .ConfigureAwait(false);
var previous = await offenseLogs.Where(log => log.Id <= id)
                                .OrderByDescending(log => log.Id)
                                .Take(2)
                                .Skip(1)
                                .FirstOrDefaultAsync()
                                .ConfigureAwait(false);
var first = await offenseLogs.OrderBy(log => log.Id)
                             .FirstOrDefaultAsync()
                             .ConfigureAwait(false);
var entry = this._mapper.Map<OffenseLog, OffenseLogDto>(current ??
                                                        throw new
                                                          Exception($"Could not find entry with id: {id}"));
entry.Next     = next?.Id;
entry.Previous = previous?.Id;
entry.First    = first.Id != entry.Id ? first.Id : null;
entry.Last     = last.Id != entry.Id ? last.Id : null;
return entry;