tags:

views:

111

answers:

3

In Sql, let's say I have the following procedure

GetCars
(
   @Ids nvarchar(MAX) = NULL       // represent a list of Id (with comma)
   @TypeIds nvarchar(MAX) = NULL   // represent a list of TypeId (with comma)
)

// After transforming my Ids and TypeIds into CSVTABLE (comma seperated values table)  

SELECT * FROM CARS 
WHERE ((@Id IS NULL) OR ( CARS.Id IN (SELECT Id FROM CSVTABLE)) AND 
      ((@TypeId IS NULL) OR (CARS.TypeId IN (SELECT ID FROM CSVTABLE)))

Is is possible to transform this sql queries into a Linq?

+1  A: 

Well, a direct translation is pretty easy:

var query = from car in dataContext.Cars
   where car.Id == null || dataContext.CsvTable.Select(x => x.Id)
                                               .Contains(car.Id)
   where car.TypeId == null || dataContext.CsvTable.Select(x => x.TypeId)
                                                   .Contains(car.TypeId)
   select car;

You'll have to try it to see if it actually creates the right SQL though.

You can simplify it somewhat:

var csvIds = dataContext.CsvTable.Select(x => x.Id);
var query = from car in dataContext.Cars
            where car.Id == null || csvIds.Contains(car.Id)
            where car.TypeId == null || csvIds.Contains(car.TypeId)
            select car;

(That may produce different SQL - I don't know, but it's worth a try.)

Jon Skeet
I think you mean "|| csvIds.Contains(car.TypeId)" for the second one.
Mark Byers
Thanks, fixed :)
Jon Skeet
I don't really have a real CSVTable in my c# code. All I have is a list of int. Also I'm using Entity-Framework, and I think there is no support for contains ...
pdiddy
Also I'm not check for Car.Id == null .... I'm interested in whether my list<int> is null or not ....
pdiddy
... and this is why you need to make your question clear. Please update the question with *all* the relevant information, and I'll take another look later.
Jon Skeet
Sorry about lack of details and thanks for taking the time to respond.
pdiddy
A: 

Just because is possible doesn't mean you should. Using @variable IS NULL OR @ variable = field (or even worse, using IN operator) is pretty much the sure shot way to trash performance.

Use explicit IF statements and separate SELECTs in T-SQL, and equivalent separate query expressions in LINQ:

IF (@ID IS NULL and @TypeID IS NO NULL)
  SELECT ... FROM CARS WHERE ...
ELSE IF (@ID IS NOT NULL AND @TypeID IS NULL)
  SELECT ... FROM CARS WHERE ...
ELSE IF (@ID IS NOT NULL AND @TypeID IS NOT NULL)
 SELECT ...

The problem with trying to build one single SELECT that satisfies different conditions depending on @variable parameters is that SQL stil has to build one query plan to cover all possible combination. Most times this plan will be the worst possible plan that does a full table scan. Even when the plan is somehow optimized, it will be optimized for the @variable values at the moment the plan was generated (due to parameter sniffing) and this plan will perform even worse than a trivial plan when @variables have different values on subsequent execution.

Remus Rusanu
thanks, i'm not an sql expert, but I understand your point. I just sometime think building all the combination of possibility is alot especially when you can have alot of parameters ....
pdiddy
A: 

I've found a solution.

that would be something like this :

List<Car> Find(List<int> carIds, List<int> carTypeIds)
{
     var carQuery = from c in ctx.Cars
                    select c;

     if(carIds!=null && carIds.Count>0)
        carQuery = carQuery.Where(c=> carIds.Contains(c.id) );


     if(carTypeIds!=null && carTypeIds.Count>0)
        carQuery = carQuery.Where(c=> carTypeIds.Contains(c.typeId) );

     return carQuery.ToList();
}
pdiddy
I thought you said Contains wasn't supported?
Jon Skeet
indeed it's not supported. I found some code using expressions to be able to do a contain.
pdiddy
here is the link to the contains for EF : http://social.msdn.microsoft.com/forums/en-US/adodotnetentityframework/thread/095745fe-dcf0-4142-b684-b7e4a1ab59f0/
pdiddy