重用 linq 查询的部分内容

发布于 2024-11-03 19:16:13 字数 1335 浏览 1 评论 0原文

我们有一个使用 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”。而且,这些查询从来都不是这么简单。他们通常按客户或当前订单进行过滤,因此更有效的查询可能是

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(不太快)

虽然我可以执行诸如 Documents.Where( ... ).GetMostRecentTimestamp() 之类的查询,但如果我尝试执行基于关联的查询(例如 MyCustomer.Orders.GetMostRecentTimestamp() ),此解决方案将失败,或 MyCustomer.Orders.AsQueryable().GetMostRecentTimestamp();

We have a program that uses Linq-To-Sql and does a lot of similar queries on our tables. In particular, we have a timestamp column, and we pull the most recent timestamp to see if the table has changed since our last query.

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

We repeat this query often on different tables that's relevant for the current form/query whatever. What I would like to do is create a "function" or something that can repeat the last 3 lines of this query (and ideally would work on every table). Here's what I would like to write:

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

But I have no idea how to create this "GetMostRecentTimestamp". Also, these queries are never this simple. They usually filter by the Customer, or by the current order, so a more valid query might be

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

Any help? Thanks!


Update [Solution]

I selected Bala R's answer, here's the code updated so it compiles:

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

The only drawback to this solution is that I will have to write this function for each table. I would have loved Tejs's answer, if it actually worked, but I'm not re-designing my database for it. Plus DateTime is a not a good way to do timestamps.


Update #2 (Not so fast)

While I can do a query such as Documents.Where( ... ).GetMostRecentTimestamp(), this solution fails if I try to do an association based query such as MyCustomer.Orders.GetMostRecentTimestamp(), or MyCustomer.Orders.AsQueryable().GetMostRecentTimestamp();

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

━╋う一瞬間旳綻放 2024-11-10 19:16:14

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

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()

This is actually pretty easy to do. You simply need to define an interface on the entities you wish to provide this for:

public class MyEntity : ITimestamp

Then, your extenstion method:

public static DateTime GetMostRecentTimestamp<T>(this IQueryable<T> queryable)
    where T : ITimestamp
{
     return queryable.Select(x => x.m_Timestamp)
            .OrderByDescending(r => r)
            .FirstOrDefault()
}

This is then useful on any entity that matches the interface:

context.Documents.GetMostRecentTimestamp()
context.SomeOtherEntity.GetMostRecentTimestamp()
平生欢 2024-11-10 19:16:14

像这样的扩展怎么样

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

How about an extension like this

public static DateTime GetMostRecentTimestamp (this IQueryable<Document> docs)
{
    return docs.Select(r => r.m_Timestamp)
               .OrderByDescending(r => r)
               .FirstOrDefault();
}
下雨或天晴 2024-11-10 19:16:14

唔...

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

Hmm...

DateTime timeStamp1 = dataContext.Customers.Max(c => c.TimeStamp);
DateTime timeStamp2 = dataContext.Orders.Max(c => c.TimeStamp);
DateTime timeStamp3 = dataContext.Details.Max(c => c.TimeStamp);
埋情葬爱 2024-11-10 19:16:14

我创建了一对可以帮助您的扩展方法: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() 更有效;然而 IQueryable 提供者无法解析它们。您可以像这样使用它们:

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

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

I created a pair of extension methods that could help you out: ObjectWithMin and 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;
    }

These two are more efficient than OrderBy().FirstOrDefault() when used on in-memory collections; however they're unparseable by IQueryable providers. You'd use them something like this:

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

ts is now the object having the most recent timestamp, so you don't need a second query to get it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文