Entity Framework - MySQL - Null Comparison! - mysql

Whats wrong with following code? :(
int? parentFolderId = null;
if( this.Request.QueryString ["folderId"] != null )
parentFolderId = Convert.ToInt32( this.Request.QueryString ["folderId"] );
f = ( from x in this.EntityDataContext.folders
where x.parent_id == parentFolderId
select x ).ToList();
It returns nothing! Though there ARE records in database with parent_id as NULL.
However, when I explicitly state NULL; it works!
f = ( from x in this.EntityDataContext.folders
where x.parent_id == null
select x ).ToList();
What could be the issue?
PS: I hate working with mysql using Entity Framework .... every damn simple thing has million issues!

Long Shot
f = ( from x in this.EntityDataContext.folders
where ((parentFolderId!=null && x.parent_id == parentFolderId)
||(parentFolderId==null && x.parent_id == null))
select x ).ToList();
Yeah, this seams wired, and I guess your first example should work just fine with MsSql.
Maybe it's time to file a bug to authors of Linq to MySql ?

I had this kind of problem in sql server and in sql server the generated query looks like "parent_id = null" when you are working on a nullable field. And that query returns nothing even parent_id is null.
The tricky way in here is, you should force EF to create a query like "parent_id is null" and the code I tried in linq was;
if(parentFolderId.HasValue)
{
f = ( from x in this.EntityDataContext.folders
where x.parent_id == parentFolderId
select x ).ToList();
}
else
{
f = ( from x in this.EntityDataContext.folders
where !x.parent_id.HasValue
select x ).ToList();
}
I know this does not seem a perfect way to do this but, this is how I could get rid of that issue.

You'll probably find there's an issue involving using DBNull or something similar. I would think that in the second case (where you explicitly state "null") that Linq is automatically transforming it to DBNull in the background.
perhaps try something along the lines of:
where x.parent_id == ( parentFolderId == null ? DBNull.Value : parentFolderId )
Hope that puts you on the right track!

This is connector bug and I have reported at mysql.

Related

How do I use 'OR' operator to return all rows if string is empty in linq to sql

I've a linq query :
var Employees = db.EmployeeMasterAs
.Where(x => x.SystemCode == SysCode && x.EmployeeCode == EmpCode)
.ToList();
the above query works fine if all values in the where clause are provided. If EmpCode is supplied a value, it returns the corresponding data, which works fine. However, I've no idea about how to return all rows if EmpCode is not supplied.
If I were to use SQL, I would have done it this way :
SELECT * FROM EmployeeMasterAs
WHERE SystemCode == #SysCode AND (EmployeeCode == #EmpCode or '')
I've no idea how to translate the above query into linq syntax. Any Help will be deeply appreciated, Thanks in Advance :)
you can even write something like this
...&& (EmpCode == null || x.EmployeeCode == EmpCode) )
which i find simplier than #Dr Ivol

Multiple conditions in linq lambda query

Three conditions in linq where clause using lambda expressions
List<Tbl_MVPConsultant> _objConsultants = _datalayer.Get_MVP_Consultants();
_objConsultants = _objConsultants.Where(p => p.Country.ToLower().Contains(SearchTextbox.ToLower()) ||
p.State.ToLower().Contains(SearchTextbox.ToLower()) ||
p.City.ToLower().Contains(SearchTextbox.ToLower())).ToList();
I'm trying to achieve a filter operation three times using the above query .. but i'm getting an error stating object reference not set to an instance of an object ..
Looking for a quick solution.Appreciate early efforts.
Thank you
You won't be able to call p.Country.ToLower if p.Country is null. Put p.Country != null && p.State != null && p.City != null && at the start of the lambda.

Using one LINQ statement with different parameters

I have a pretty complex linq statement I need to access for different methods. Each of these methods may need to see the resulting data with different parameters. For one method it may be a project code, for another it may be language. The statement is pretty much the same it's just the where part which changes.
I have not been able to figure out how to use different where statements without duplicating the entire linq statement, and that just isn't dry enough for me.
For example (greatly simplified):
var r = from c in customer
where c.name == "some name"
// or it may be
var r = from c in customer
where c.customerId == 8
Is there a way to have both of these in the same statement so I can use one or the other based on what I am doing? I tried an if statement to use one of the where statements or the other, and that didn't go over very well.
You can do it like this:
var r = from c in customer
select c;
if (CustomerName != null)
r = r.Where(c => c.name == CustomerName);
if (CustomerID != null)
r = r.Where(c => c.customerId == CustomerID);
You could make these else if if only one should apply, in my example any criteria that wasn't null would be applied to the query to filter on.
what about something like this?
var useIdForFiltering = false;
var r = from c in customer
where (useIdForFiltering && c.customerId == 8) || (c.name == "some name")
You can pass in a Func delegate to your function (the Where clause takes a Func delegate with a boolean return type). Then use this delegate in the Where clause.

Custom orderby in linq to sql

I've already searched the archives but can't find a solution that works for linq to sql.
How do you create a custom orderby in linq to sql so that it generates SQL code like this
ORDER BY
CASE SEASON
WHEN 'WINTER' THEN 1
WHEN 'SPRING' THEN 2
WHEN 'SUMMER' THEN 3
WHEN 'AUTUMN' THEN 4
END
Note that custom comparators dont seem to compile and OrderByWeight as seen in this tutorial (http://www.skindog.co.uk/2009/03/18/custom-sorting-order-in-linq-order-by-weighting/) doesn't seem to exist
Note
I want the ordering to happen on the sql server and not in c# as this will give me different results since I am partitioning my results.
Here is an approach using a lambda expression
MyTable
.OrderBy (t => (t.Season == "Winter") ? 1 : (t.Season == "Spring") ? 2 : [...])
.Select (
t => new
{
MyColumn = t.MyColumn
...
}
)
You must select your data first in an inner loop like you did, then select data from that result and sort normally on your custom column:
(off my head)
from s in
(from x in y select new { Sort = x.z == 'WINTER' ? 1 : x.z == 'SPRING' ? 2 : [...], Data = x })
orderby s.Sort
select s.Data
Something like that
Hope this helps

How can I speed up this linq to sql function?

I have a function (called "powersearch", the irony!) that searches for a set of strings across a bunch(~ 5) of fields.
The words come in as one string and are separated by spaces.
Some fields can have exact matches, others should have "contains".
(Snipped for brevety)
//Start with all colors
IQueryable<Color> q = db.Colors;
//Filter by powersearch
if (!string.IsNullOrEmpty(searchBag.PowerSearchKeys)){
foreach (string key in searchBag.SplitSearchKeys(searchBag.PowerSearchKeys)
.Where(k=> !string.IsNullOrEmpty(k))){
//Make a local copy of the var, otherwise it gets overwritten
string myKey = key;
int year;
if (int.TryParse(myKey, out year) && year > 999){
q = q.Where(c => c.Company.Name.Contains(myKey)
|| c.StockCode.Contains(myKey)
|| c.PaintCodes.Any(p => p.Code.Equals(myKey))
|| c.Names.Any(n => n.Label.Contains(myKey))
|| c.Company.CompanyModels.Any(m => m.Model.Name.Contains(myKey))
|| c.UseYears.Any(y => y.Year.Equals(year))
);
}
else{
q = q.Where(c => c.Company.Name.Contains(myKey)
|| c.StockCode.Contains(myKey)
|| c.PaintCodes.Any(p => p.Code.Contains(myKey))
|| c.Names.Any(n => n.Label.Contains(myKey))
|| c.Company.CompanyModels.Any(m => m.Model.Name.Equals(myKey))
);
}
}
}
Because the useYear count is rather large, I tried to check for it as little as possible by outruling all numbers that can never be a number that makes sence in this case. Similar checks are not possible on the other fields since they can pretty much contain any thinkable string.
Currently this query takes about 15 secs for a single, non-year string. That's too much.
Anything I can do to improve this?
--Edit--
Profiler shows me the following info for the part where the string is not a year:
exec sp_reset_connection
Audit login
exec sp_executesql N'
SELECT COUNT(*) AS [value]
FROM [dbo].[CLR] AS [t0]
INNER JOIN [dbo].[CO] AS [t1] ON [t1].[CO_ID] = [t0].[CO_ID]
WHERE
([t1].[LONG_NM] LIKE #p0)
OR ([t0].[EUR_STK_CD] LIKE #p1)
OR (EXISTS(
SELECT NULL AS [EMPTY]
FROM [dbo].[PAINT_CD] AS [t2]
WHERE ([t2].[PAINT_CD] LIKE #p2)
AND ([t2].[CLR_ID] = [t0].[CLR_ID])
AND ([t2].[CUSTOM_ID] = [t0].[CUSTOM_ID])
)
)OR (EXISTS(
SELECT NULL AS [EMPTY]
FROM [dbo].[CLR_NM] AS [t3]
WHERE ([t3].[CLR_NM] LIKE #p3)
AND ([t3].[CLR_ID] = [t0].[CLR_ID])
AND ([t3].[CUSTOM_ID] = [t0].[CUSTOM_ID])
)
) OR (EXISTS(
SELECT NULL AS [EMPTY]
FROM [dbo].[CO_MODL] AS [t4]
INNER JOIN [dbo].[MODL] AS [t5] ON [t5].[MODL_ID] = [t4].[MODL_ID]
WHERE ([t5].[MODL_NM] = #p4)
AND ([t4].[CO_ID] = [t1].[CO_ID])
)
)
',N'#p0 varchar(10),#p1 varchar(10),#p2 varchar(10),#p3 varchar(10),#p4 varchar(8)',#p0='%mercedes%',#p1='%mercedes%',#p2='%mercedes%',#p3='%mercedes%',#p4='mercedes'
(took 3626 msecs)
Audit Logout (3673 msecs)
exec sp_reset_connection (0msecs)
Audit login
exec sp_executesql N'
SELECT TOP (30)
[t0].[CLR_ID] AS [Id],
[t0].[CUSTOM_ID] AS [CustomId],
[t0].[CO_ID] AS [CompanyId],
[t0].[EUR_STK_CD] AS [StockCode],
[t0].[SPCL_USE_CD] AS [UseCode],
[t0].[EFF_IND] AS [EffectIndicator]
FROM [dbo].[CLR] AS [t0]
INNER JOIN [dbo].[CO] AS [t1] ON [t1].[CO_ID] = [t0].[CO_ID]
WHERE
([t1].[LONG_NM] LIKE #p0)
OR ([t0].[EUR_STK_CD] LIKE #p1)
OR (EXISTS(
SELECT NULL AS [EMPTY]
FROM [dbo].[PAINT_CD] AS [t2]
WHERE ([t2].[PAINT_CD] LIKE #p2)
AND ([t2].[CLR_ID] = [t0].[CLR_ID])
AND ([t2].[CUSTOM_ID] = [t0].[CUSTOM_ID])
)
)
OR (EXISTS(
SELECT NULL AS [EMPTY]
FROM [dbo].[CLR_NM] AS [t3]
WHERE ([t3].[CLR_NM] LIKE #p3)
AND ([t3].[CLR_ID] = [t0].[CLR_ID])
AND ([t3].[CUSTOM_ID] = [t0].[CUSTOM_ID])
)
)
OR (EXISTS(
SELECT NULL AS [EMPTY]
FROM [dbo].[CO_MODL] AS [t4]
INNER JOIN [dbo].[MODL] AS [t5] ON [t5].[MODL_ID] = [t4].[MODL_ID]
WHERE ([t5].[MODL_NM] = #p4)
AND ([t4].[CO_ID] = [t1].[CO_ID])
)
)'
,N'#p0 varchar(10),#p1 varchar(10),#p2 varchar(10),#p3 varchar(10),#p4 varchar(8)',#p0='%mercedes%',#p1='%mercedes%',#p2='%mercedes%',#p3='%mercedes%',#p4='mercedes'
(took 3368 msecs)
The database structure, sadly, is not under my control. It comes from the US and has to stay in the exact same format for compatibility reasons. Although most of the important fields are indeed indexed, they are indexed in (unnecessary) clustered primary keys. There's verry little I can do about that.
Okay, let's break this down - the test case you're interested in first is a single non-year, so all we've got is this:
q = q.Where(c => c.Company.Name.Contains(myKey)
|| c.StockCode.Contains(myKey)
|| c.PaintCodes.Any(p => p.Code.Contains(myKey))
|| c.Names.Any(n => n.Label.Contains(myKey))
|| c.Company.CompanyModels.Any(m => m.Model.Name.Equals(myKey))
Am I right? If so, what does the SQL look like? How long does it take just to execute the SQL statement in SQL Profiler? What does the profiler say the execution plan looks like? Have you got indexes on all of the appropriate columns?
Use compiled queries.
If you don't, you will lose up to 5-10x times performance, as LINQ-to-SQL will have to generate SQL from query every time you call it.
Things become worse when you use non-constants in LINQ-to-SQL as getting their values is really slow.
This assumes that you already have indexes and sane DB schema.
BTW, I am not kidding about 5-10x part.