简体   繁体   English

使用Lambda,Linq,Entity Framework选择值的更改

[英]Selecting changes in values with Lambda, Linq, Entity Framework

I have the following Entity Framework class definition: 我有以下Entity Framework类定义:

class TimeValue
{
    DateTime StartDate;
    double Value;
}

Say given the following series of values I only want to know when the Value changes: 假设给出以下一系列值,我只想知道值何时更改:

2000-01-01  100
2000-01-15  100
2000-02-01  110
2000-02-15  120
2000-03-01  120
2000-03-15  50
2000-04-01  50
2000-04-15  50
2000-05-01  120

So the result would be: 结果将是:

2000-01-01  100
2000-02-01  110
2000-02-15  120
2000-03-15  50
2000-05-01  120

I can select the values fine using lambda/linq. 我可以使用lambda / linq选择合适的值。 Then I iterate through the results using the following code to add to a list: 然后我使用以下代码迭代结果以添加到列表:

var timeValueQuery = _context.TimeValues.Where(...);

List<TimeValue> timeChanges = new List<TimeValue>();
TimeValue lastValue = null;
foreach (var tvq in timeValueQuery)
{
    if (lastValue == null || tvq.Value != lastValue.Value)
    {
        timeChanges.Add(tvq);
    }
    lastValue = tvq;
}

Just wondered if there was a quicker/nicer way to do it. 只是想知道是否有更快/更好的方法来做到这一点。

You can create extension method which will return item only if some condition is met. 您可以创建仅在满足某些条件时才返回项目的扩展方法。 This condition (predicate) will accepts two parameters - previous and current item, which it should compare: 这个条件(谓词)将接受两个参数 - 上一个和当前项,它应该比较:

public static IEnumerable<T> TakeIf<T>(this IEnumerable<T> source, 
                                       Func<T, T, bool> predicate)
{
    var enumerator = source.GetEnumerator();
    if (!enumerator.MoveNext())
        yield break;

    yield return enumerator.Current;
    T previous = enumerator.Current;

    while (enumerator.MoveNext())
    {
        T current = enumerator.Current;
        if (predicate(previous, current))
            yield return current;

        previous = current;
    }
}

Pass predicate which checks if previous and current items have different values. 传递谓词,检查先前和当前项目是否具有不同的值。 Usage: 用法:

var timeChanges = _context.TimeValues.TakeIf((x, y) => x.Value != y.Value);

Edited after reading your dataset again. 在再次读取数据集后编辑。

I see a grouping wouldn't work. 我看到分组不起作用。 Ideally though, you want this logic on the db server, not client side due to network io, etc. 理想情况下,由于网络io等原因,您希望在数据库服务器上使用此逻辑,而不是客户端。

You can either write this as a proc or dynamic sql. 您可以将其写为proc或动态sql。 Dynamic sql maybe easier in the near term. 动态sql在短期内可能更容易。

Simple method, select it into a cursor. 简单的方法,选择它进入游标。 Loop into a temp table variable and return the result set. 循环到临时表变量并返回结果集。

If you dataset is really small, then stick with the easy to read linq loop you have. 如果您的数据集非常小,那么请坚持使用易读的linq循环。 Don't add more complexity unless you need too. 除非您需要,否则不要增加复杂性。 ie don't micro-optimize. 即不要微观优化。

Don't know if this is nicer :) anyway: 不知道这是不是更好:)反正:

  IQueryable<TimeValue> values = ...; // initialize here
  var query = from v in values
              where (from v2 in values
                     orderby v2.StartDate
                     where v2.StartDate > v.StartDate
                     select v2.Value).FirstOrDefault() != v.Value
              select v;

If zero value is possible, change FirstOrDefault() to FirstOrDefault(impossible_value). 如果可以为零,则将FirstOrDefault()更改为FirstOrDefault(impossible_value)。 Also for cycle may be more efficient (but you asked for LINQ). 对于循环也可能更有效(但你要求LINQ)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM