简体   繁体   中英

ASP.NET C# Linq to SQL appears to be doing OR instead of AND

I have a Linq to SQL query that appears to be producing the right SQL but the results are not the same as if I run the query directly in SQL Management Studio Express.

My C# code is:

using (DataClasses1DataContext dc = new DataClasses1DataContext())
        {
            var q = from s in dc.tbContentDetails
                    where s.Active == true && s.SupervisorApproved == true
                    select s;
            foreach (string st in result2)
            {
                q = from s in q
                    where s.Fuzzy.Contains("|" + st + "|")
                    select s;
            }
            lblResults.Text = q.Count().ToString();
            repResults.DataSource = q.Take(10);
            repResults.DataBind();
        }

The SQL generated is (field list replaced with "..."):

SELECT [t0].[ContentDetailId], ... FROM [dbo].[tbContentDetail] AS [t0]
WHERE ([t0].[Fuzzy] LIKE @p0) AND ([t0].[Fuzzy] LIKE @p1)
AND ([t0].[Fuzzy] LIKE @p2) AND ([t0].[Active] = 1)
AND ([t0].[SupervisorApproved] = @p3)

If I run this query directly I get the expected results but when it runs in Linq I get many more search results, exactly the same as if all the "Fuzzy LIKE" in the where clause are joined with OR not AND.

If I put all the "Fuzzy.Contains" in to one Linq statement it does work fine but as I need to allow for any number of keywords I chose this way of building my query. Perhaps this is not the right way to do this or is there some other problem here?

It seems, like delayed execution strikes back. The filter is executed, after loop is completed. Your's filter uses variable ST during execution, that, at the moment of execution will have value, equals to last value in the result2 array.

Quick fix would be to copy st variable to local variable:

    using (DataClasses1DataContext dc = new DataClasses1DataContext())
    {
        var q = from s in dc.tbContentDetails
                where s.Active == true && s.SupervisorApproved == true
                select s;
        foreach (string st in result2)
        {
            var tmp = st;
            q = from s in q
                where s.Fuzzy.Contains("|" + tmp + "|")
                select s;
        }
        lblResults.Text = q.Count().ToString();
        repResults.DataSource = q.Take(10);
        repResults.DataBind();
    }

This explains, why foreach statement behaves like this, inside closure.

You are setting q inside the loop so essentially when you are setting the data source, q is set just by the last iteration of the loop making all other iterations useless. I'm not sure if that's what you desire. I'm just guessing but I think you need something like this

 var q = from s in dc.tbContentDetails
                where s.Active == true && s.SupervisorApproved == true &&
                results2.Any(r => s.Fuzzy.Contains("|" + r + "|")
                select s;

EDIT: not very optimal but for linq to sql, try this

   var q = from s in dc.tbContentDetails
                    where s.Active == true && s.SupervisorApproved == true &&
                    select s;
   q = q.ToList().Where(s => results2.Any(r => s.Fuzzy.Contains("|" + r + "|"));

I think "q" gets reused which is causing the behaviour.

try changing q = from s in q to var q2 = from s in q

EDIT 2 (after reading the comment) - remove the foreach and try this:

var Result = from s in dc.tbContentDetails
             from st in result2 
             where s.Active == true and s.SupervisorApproved == true 
             and s.Fuzzy.Contains("|" + st + "|")
             select s;

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