4

I am trying to join tables using LINQ by matching columns where a column in the joined table is equal to a variable or the variable is null (at which point the join still needs to happen just not on that field).

My LINQ is something like:

var data = (
    from lt in cxt.CmsPageRow
    join page in cxt.CmsPage on new { lt.CmsPageID, cmsSiteID.Value } equals new { page.CmsPageID, page.CmsSiteID }
    ...

cmsSiteID is a nullable INT.

I cannot compile my code as it is complaining about "Type inference failed in the call to 'Join'."

On top of that I need to only join on page.CmsSiteID when cmsSiteID is not null. If cmsSiteID is null then the join on lt.CmsPageID still needs to happen.

* EDIT *

The question has kind of changed now. I can get it to do what I want by using a WHERE clause on the join in my LINQ.

join page in cxt.CmsPage.Where(p=>(cmsSiteID==0||p.CmsSiteID==cmsSiteID)) on lt.CmsPageID equals page.CmsPageID

However, this still runs slow. If I change the parameter passed through to a literal it executes instantly.

Slow runner

(@p__linq__1 = 0 OR [Extent2].[CmsSiteID] = @p__linq__1)

Fast runner

(267 = 0 OR [Extent2].[CmsSiteID] = 267)

Is there a way to speed this up?

4

1 回答 1

2

join in LINQ assumes an inner join (no nulls). Try pulling the null stuff out into separate where clauses. I think something along these lines should work for what you're describing.

from lt in cxt.CmsPageRow
join page in cxt.CmsPage on lt.CmsPageID == page.CmsPageID
where cmsSiteID == null || 
      (cmsSiteID != null && (page.CmsSiteID == null || page.CmsSiteId == cmsSiteID.Value))
select ...

Update

I didn't realize that performance was an issue for you. In that case, I'd suggest creating a different query structure based on values that are known at run-time and don't depend on individual rows:

var rows = 
    from lt in cxt.CmsPageRow
    join page in cxt.CmsPage on lt.CmsPageID == page.CmsPageID
    select new {lt, page};
if (cmsSiteID != null)
{
    rows = rows.Where(r => r.page.CmsSiteID == null || 
                           r.page.CmsSiteId == cmsSiteID.Value));
}
var data = rows.Select(...);

Also, if your data context is set up right, you should be able to use navigation properties to simplify your code somewhat.

var rows = ctx.CmsPageRow;
if (cmsSiteID != null)
{
    rows = rows.Where(r => r.CmsPage.Any(p => p.CmsSiteID == null || 
                               p.CmsSiteId == cmsSiteID.Value));
}
var data = rows.Select(...);
于 2013-02-22T00:12:23.230 回答