简体   繁体   中英

How to specify a custom method in a LINQ query (C# Entity Framework)

I have defined a super class "Validity" which defines a time span (ValidFrom / ValidTo) in which an object is "valid". It also defines a function that returns true for a given timestamp, iff (=if and only if) a (derived) object is valid at this time.

public class Validity
{
    public int ValidityID { get; set; }

    public DateTime? ValidFrom { get; set; }
    public DateTime? ValidTo { get; set; }

    bool isValidAt(DateTime time)
    {
        return (ValidFrom == null || ValidFrom >= time)
            && (ValidTo == null || ValidTo < time);
    }
}

Now I would like to write some function that checks isValidAt within a LINQ query. I guess this is possible via IQueriable, but I didn't find out how... The following code snipped is what I want to have "working" in some way (especially the where n.isValidAt(t) ). So, how can this be achieved?

public class Node : Validity {
    public int NodeID { get; set; }

    public static getFirstNode(DateTime t)
    {
        MyContext db = new MyContext();
        var items = from n in db.Nodes
                     where n.isValidAt(t)
                     orderby n.NodeID descending
                     select n;
        return items.FirstOrDefault<Node>();
    }
}

--- WORKING SOLUTION ---

I needed to adapt the solution of Zaid Masud a bit, to get it working. Note that I had to remove the this in the parameter list (now the method definition is public static IQueryable<T> isValidAt<T>(IQueryable<T> query, DateTime time) where T : Validity ). Here is the source code:

public class Validity
{
    public int ValidityID { get; set; }

    public DateTime? ValidFrom { get; set; }
    public DateTime? ValidTo { get; set; }

    public static IQueryable<T> isValidAt<T>(IQueryable<T> query, DateTime time) where T : Validity
    {
        return query.Where<T>(c => (c.ValidFrom == null || c.ValidFrom >= time)
            && (c.ValidTo == null || c.ValidTo < time));
    }
}

You need to declare your bool isValidAt(DateTime time) method as protected so the derived class can access it:

protected bool IsValidAt(DateTime time)

However, after you get this compiling, I doubt that your LINQ to SQL provider will be able to translate the query to SQL. You will probably need to embed the logic inside your LINQ query and write something like:

var items = from n in db.Nodes
            where (n.ValidFrom == null || n.ValidFrom >= t) && (n.ValidTo == null || n.ValidTo < t)
            orderby n.NodeID descending
            select n;

This will work, but a better alternative is to create the following kind of extension method:

public static class ValidityExtensions
{
    public static IQueryable<T> Valid<T>(this IQueryable<T> validities, DateTime time) where T : Validity
    {
        return validities.Where(v => (v.ValidFrom == null || ValidFrom >= time) && (v.ValidTo == null || v.ValidTo < time));
    }
}

Now you can use this as follows:

var items = from n in db.Nodes.Valid(time)
            orderby n.NodeID descending
            select n;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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