我们有一个使用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
现在是具有最近时间戳的对象,因此您不需要第二个查询来获取它。