Vadim Alekseevsky
Vadim Alekseevsky

Reputation: 487

Issue With LINQ and Reference List

I Have following code with LINQ

var q = (from web in DataContext.Webs select web);
List<int?> k1 = new List<int?>() { 1, 2 };
List<int?> k2=new List<int?>() { 16, 17 };
            q = q.Where(web => DataContext.WebTechMaps.Any(t => t.WebsiteId == web.WebsiteId && k1.Contains(t.TechId)));
            System.Diagnostics.Debug.WriteLine(q.Count());
            k1 = k2;
            q = q.Where(web => DataContext.WebTechMaps.Any(t => t.WebsiteId == web.WebsiteId && k1.Contains(t.TechId)));
            System.Diagnostics.Debug.WriteLine(q.Count());

Here Is what query it generates.

First Execution of count.

SELECT COUNT(*) AS [value]
FROM [dbo].[Web] AS [t0]
WHERE EXISTS(
    SELECT NULL AS [EMPTY]
    FROM [dbo].[WebTechMap] AS [t1]
    WHERE ([t1].[WebsiteId] = ([t0].[WebsiteId])) AND ([t1].[TechId] IN (@p0, @p1))
    )
-- @p0: Input Int (Size = -1; Prec = 0; Scale = 0) [1]
-- @p1: Input Int (Size = -1; Prec = 0; Scale = 0) [2]

Second Execution of count function

SELECT COUNT(*) AS [value]
FROM [dbo].[Web] AS [t0]
WHERE (EXISTS(
    SELECT NULL AS [EMPTY]
    FROM [dbo].[WebTechMap] AS [t1]
    WHERE ([t1].[WebsiteId] = ([t0].[WebsiteId])) AND ([t1].[TechId] IN (@p0, @p1))
    )) AND (EXISTS(
    SELECT NULL AS [EMPTY]
    FROM [dbo].[WebTechMap] AS [t2]
    WHERE ([t2].[WebsiteId] = ([t0].[WebsiteId])) AND ([t2].[TechId] IN (@p2, @p3))
    ))
-- @p0: Input Int (Size = -1; Prec = 0; Scale = 0) [16]
-- @p1: Input Int (Size = -1; Prec = 0; Scale = 0) [17]
-- @p2: Input Int (Size = -1; Prec = 0; Scale = 0) [16]
-- @p3: Input Int (Size = -1; Prec = 0; Scale = 0) [17]

Please Take a look at the parameters passed to query.

Seems it uses the new referenced object for both Expressions.

Somehow @p0 and @p1 change their old values. I understand that issue is in Linq it uses new referenced object.

-- @p0: Input Int (Size = -1; Prec = 0; Scale = 0) [1]
-- @p1: Input Int (Size = -1; Prec = 0; Scale = 0) [2]



-- @p0: Input Int (Size = -1; Prec = 0; Scale = 0) [16]
-- @p1: Input Int (Size = -1; Prec = 0; Scale = 0) [17]
-- @p2: Input Int (Size = -1; Prec = 0; Scale = 0) [16]
-- @p3: Input Int (Size = -1; Prec = 0; Scale = 0) [17]

Can someone explain how to use same name of List object but keep the query using correct List's

Desired output is

-- @p0: Input Int (Size = -1; Prec = 0; Scale = 0) [1]
-- @p1: Input Int (Size = -1; Prec = 0; Scale = 0) [2]
-- @p2: Input Int (Size = -1; Prec = 0; Scale = 0) [16]
-- @p3: Input Int (Size = -1; Prec = 0; Scale = 0) [17]

Thanks in Advance

Upvotes: 4

Views: 300

Answers (1)

Jon Skeet
Jon Skeet

Reputation: 1500105

Your first query expression uses k1. It uses the variable kl, and that's what's captured. When you change the value of k1, that's effectively changing the meaning of the query. If you don't want the meaning of the query to change, don't change the captured variables! Just use k2 in your second filter:

var q = (from web in DataContext.Webs select web);
List<int?> k1 = new List<int?>() { 1, 2 };
List<int?> k2=new List<int?>() { 16, 17 };
q = q.Where(web => DataContext.WebTechMaps
                              .Any(t => t.WebsiteId == web.WebsiteId && 
                                        k1.Contains(t.TechId)));
System.Diagnostics.Debug.WriteLine(q.Count());
q = q.Where(web => DataContext.WebTechMaps
                              .Any(t => t.WebsiteId == web.WebsiteId &&
                                   k2.Contains(t.TechId)));
System.Diagnostics.Debug.WriteLine(q.Count());

Upvotes: 4

Related Questions