none
Confusing Problem - Hard to explain in one line! RRS feed

  • Question

  • In the code below MgrIDs is a List of manager User IDs - strings.  Example is for two manager User IDs.


    Below is part of problem where I am trying to Union a set of queries.  Each query is created from a manager User ID.  A query produces the employees under a manager.  The Union would be all employees under all managers.

    The foreach loop does not work.  I get only one unique query based on the last manager User ID.  Thus, I only get the employees under one manager.   If I use either of the quoted lines of code it works.  I get  a  Union of two queries.

    Why does the foreach loop not work?

    Jay


     


    List<IQueryable<Head>> Query = new List<IQueryable<Head>>();

    foreach (string mgrid in MgrIDs)
    {
        Query.Add(db.Heads.Where(H => H.newPath.Contains(mgrid)));
    }

    //Query.Add(db.Heads.Where(H => H.newPath.Contains("xxx")));
    //Query.Add(db.Heads.Where(H => H.newPath.Contains("yyy")));

    //Query.Add(db.Heads.Where(H => H.newPath.Contains(MgrIDs[0])));
    //Query.Add(db.Heads.Where(H => H.newPath.Contains(MgrIDs[1])));

    return Query[1].Union(Query[0]);

    Thursday, March 12, 2009 2:42 AM

Answers

  • This is a problem that is caused by how C# encodes references to local variables in anonymous methods (and queries).  Instead of encoding the value held by the variable, it encodes the reference to the variable.  So if you go in a loop and create multiple instances of anonymous methods (or queries) each one will simply refer back to that single variable. Later, when you ask them to run they evaluate that variable and they all come up with the value it last held.

    You don't need a new query, you need a new variable to hold the string.  You don't have to allocate anything, just declare a new variable.  Since it is inside the scope of the loop it will be a logically different variable each time. 

    List<IQueryable<Head>> Query = new List<IQueryable<Head>>();

    foreach (string mgrid in MgrIDs)
    {
        string id = mgrid;
        Query.Add(db.Heads.Where(H => H.newPath.Contains(id)));
    }


    You could also do this:

    var queries = MgrIds.Select(id => db.Heads.Where(h => h.newPath.Contains(id)).ToList();


    Wayward LINQ Lacky
    Thursday, March 12, 2009 3:30 PM
    Moderator

All replies

  • I see the problem.  I need something like the following:

    foreach (string mgrid in MgrIDs)
    {
        IQueryable<Head> x = new IQueryable<Head>();
        x = db.Heads.Where(H => H.newPath.Contains(mgrid));
        Query.Add(x);
    }

    I somehow need to create a new object for each iteration of the foreach loop but I cannot do this because IQueryable is an interface.

    HELP!!

    Jay

    Thursday, March 12, 2009 10:19 AM
  • This is a problem that is caused by how C# encodes references to local variables in anonymous methods (and queries).  Instead of encoding the value held by the variable, it encodes the reference to the variable.  So if you go in a loop and create multiple instances of anonymous methods (or queries) each one will simply refer back to that single variable. Later, when you ask them to run they evaluate that variable and they all come up with the value it last held.

    You don't need a new query, you need a new variable to hold the string.  You don't have to allocate anything, just declare a new variable.  Since it is inside the scope of the loop it will be a logically different variable each time. 

    List<IQueryable<Head>> Query = new List<IQueryable<Head>>();

    foreach (string mgrid in MgrIDs)
    {
        string id = mgrid;
        Query.Add(db.Heads.Where(H => H.newPath.Contains(id)));
    }


    You could also do this:

    var queries = MgrIds.Select(id => db.Heads.Where(h => h.newPath.Contains(id)).ToList();


    Wayward LINQ Lacky
    Thursday, March 12, 2009 3:30 PM
    Moderator