简体   繁体   中英

Is it possible to store, or pre-define a LINQ query for re-use?

I currently have a linq query that i use about 5 times within the same MVC class, is it possible to define the query somewhere within the page in the same way you can public const a string or an int , without having to create a method which calls the linq query?

ie

const LinqQuery myQuery = from cat in db.Categories where cat.CategoryID != null select cat;

...

public ActionResult Edit(long id = 0)
{
    ViewBag.ParentCategoryID = myQuery;
    ...
}

public ActionResult Create()
{
    ViewBag.ParentCategoryID = myQuery;
    ...
}

From what i can see, the only way is creating a method, but i would like to avoid it if there is a nicer way of doing things.

My crystal ball tells me that Linq queries are only executed when you iterate over the result so:

static List<int> list = new List<int> { 1, 2, 3 };
static IEnumerable<int> result = from i in list where i > 2 select i;

static void Main(string[] args)
{
    Console.WriteLine(result.Sum()); // 3
    list.Add(5);
    Console.WriteLine(result.Sum()); // 8
}

MSDN Has an article on precompiled queries:

http://msdn.microsoft.com/en-us/library/bb399335.aspx

In your example it could look something like this:

public static readonly Func<MyContext, int, IQueryable<Category>>
    myQuery = CompiledQuery.Compile((MyContext db, int categoryID) =>
            from cat in db.Categories where cat.CategoryID == categoryID select cat);

I added readonly as it is going to be the closest you'll get to a constant.

Yes, just put it in the constructor (I assume the type of db.Catagories is Catagory )

public class ClassName
{
    public ClassName()
    {
        db =  //do whatever is needed to initialize the db context
        myQuery = from cat in db.Categories where cat.CategoryID != null select cat;
    }

    DataSourceContext db;
    IQueryable<Catagory> myQuery;

    public ActionResult Edit(long id = 0)
    {
        ViewBag.ParentCategoryID = myQuery;
        ...
    }

    public ActionResult Create()
    {
        ViewBag.ParentCategoryID = myQuery;
        ...
    }
}

This could also be done in the static constructor with static members if access to db is done in a thread safe manner (via internally inside DataSourceContext or by you in defensive coding)


However a better way would be to call a static function that returns the query you want and passing in the context of the database you want to connect to.

public static IQueryable<Catagory> NonNullCatagoriesQuery(DataSourceContext db)
{
    return from cat in db.Categories where cat.CategoryID != null select cat;
}

Then in your code you just do

public ActionResult Edit(long id = 0)
{
    ViewBag.ParentCategoryID = NonNullCatagoriesQuery(db);
    ...
}

public ActionResult Create()
{
    ViewBag.ParentCategoryID = NonNullCatagoriesQuery(db);
    ...
}

You also could move the function in to a repository class that held the db context too so you would not need to pass it in, but you did not include in your code example how you got db .

You're in luck, sorta, While it's similar, you can declare a Func<> and call that. It looks cleaner / nicer than a method when you only have a very simple instruction you want to execute.

Here's sorta an example on their implementation (This is from a project where I had to use SetWindowPos multiple times along with some other stuff):

Func<Process, winPosData, bool> swp = (p, w) => SetWindowPos(p.MainWindowHandle, (IntPtr)w.hWndInsertAfter, w.x, w.y, w.cx, w.cy, w.uFlags);

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