重用linq查询的部分



我们有一个使用Linq-To-Sql的程序,在我们的表上做了很多类似的查询。特别是,我们有一个时间戳列,我们提取最近的时间戳来查看表自上次查询以来是否发生了更改。

System.Data.Linq.Binary ts;
ts = context.Documents
    .Select(r => r.m_Timestamp)
    .OrderByDescending(r => r)
    .FirstOrDefault();

我们经常在与当前表单/查询相关的不同表上重复这个查询。我要做的是创建一个函数或者可以重复这个查询的最后3行(理想情况下可以在每个表上工作)。下面是我想写的:

System.Data.Linq.Binary ts;
ts = context.Documents
    .GetMostRecentTimestamp();

但是我不知道如何创建这个"getmostrecenttimestamp"。此外,这些查询从来没有这么简单。它们通常按Customer或当前订单进行过滤,因此更有效的查询可能是

ts = context.Documents
    .Where(r => r.CustomerID == ThisCustomerID)
    .GetMostRecentTiemstamp(); 

帮忙吗?谢谢!


更新(解决方案)

我选择了Bala R的答案,这里是更新的代码,所以它编译:

public static System.Data.Linq.Binary GetMostRecentTimestamp(this IQueryable<Data.Document> docs)
{
    return docs
        .Select(r => r.m_Timestamp)
        .OrderByDescending(r => r)
        .FirstOrDefault();
    }

这个解决方案的唯一缺点是我必须为每个表编写这个函数。如果Tejs的答案真的有效,我会喜欢它,但我不会为此重新设计我的数据库。加上DateTime不是一个很好的方式来做时间戳。


更新#2(没那么快)

虽然我可以做一个查询,如文档。在哪里(……).GetMostRecentTimestamp(),这个解决方案失败,如果我尝试做一个基于关联的查询,如MyCustomer.Orders.GetMostRecentTimestamp(),或MyCustomer.Orders.AsQueryable().GetMostRecentTimestamp();

这实际上很容易做到。您只需要在希望提供此功能的实体上定义一个接口:

public class MyEntity : ITimestamp
然后,你的扩展方法:
public static DateTime GetMostRecentTimestamp<T>(this IQueryable<T> queryable)
    where T : ITimestamp
{
     return queryable.Select(x => x.m_Timestamp)
            .OrderByDescending(r => r)
            .FirstOrDefault()
}

这在任何匹配接口的实体上都是有用的:

context.Documents.GetMostRecentTimestamp()
context.SomeOtherEntity.GetMostRecentTimestamp()

这样的扩展怎么样

public static DateTime GetMostRecentTimestamp (this IQueryable<Document> docs)
{
    return docs.Select(r => r.m_Timestamp)
               .OrderByDescending(r => r)
               .FirstOrDefault();
}

嗯…

DateTime timeStamp1 = dataContext.Customers.Max(c => c.TimeStamp);
DateTime timeStamp2 = dataContext.Orders.Max(c => c.TimeStamp);
DateTime timeStamp3 = dataContext.Details.Max(c => c.TimeStamp);

我创建了一对可以帮助您的扩展方法:ObjectWithMin和ObjectWithMax:

public static T ObjectWithMax<T, TResult>(this IEnumerable<T> elements, Func<T, TResult> projection)
        where TResult : IComparable<TResult>
    {
        if (elements == null) throw new ArgumentNullException("elements", "Sequence is null.");
        if (!elements.Any()) throw new ArgumentException("Sequence contains no elements.");
        var seed = elements.Select(t => new {Object = t, Projection = projection(t)}).First();
        return elements.Aggregate(seed,
                                  (s, x) =>
                                  projection(x).CompareTo(s.Projection) >= 0
                                      ? new {Object = x, Projection = projection(x)}
                                      : s
            ).Object;
    }
public static T ObjectWithMin<T, TResult>(this IEnumerable<T> elements, Func<T, TResult> projection)
        where TResult : IComparable<TResult>
    {
        if (elements == null) throw new ArgumentNullException("elements", "Sequence is null.");
        if (!elements.Any()) throw new ArgumentException("Sequence contains no elements.");
        var seed = elements.Select(t => new {Object = t, Projection = projection(t)}).First();
        return elements.Aggregate(seed,
                                  (s, x) =>
                                  projection(x).CompareTo(s.Projection) < 0
                                      ? new {Object = x, Projection = projection(x)}
                                      : s
            ).Object;
    }

这两个在内存集合上使用时比OrderBy().FirstOrDefault()更有效;然而,它们无法被可查询的提供者解析。你可以这样使用它们:

ts = context.Documents
    .Where(r => r.CustomerID == ThisCustomerID)
    .ObjectWithMax(r=>r.m_Timestamp);

ts现在是具有最近时间戳的对象,因此您不需要第二个查询来获取它。

相关内容

  • 没有找到相关文章

最新更新