NHibernate.ISession.Linq<T>.Where(expression) retrieves whole table - mysql

I am using NHIbernate against MySql, and when I use the following statement, NHibernate Profiler shows me that the query passed to MySql is basically SELECT * FROM tablename with NO WHERE clause. The LINQ expression isn't applied until after all the data are retrieved. This is obviously not acceptable from a performance standpoint. What am I doing wrong?
Session.Linq<T>().Where(expression).AsQueryable()
Thanks!
[UPDATE]
As #GertArnold guessed, the call preceding this was:
public IQueryable<Student> FindByExpression(Func<Student, bool> expression)
The expression was:
_studentRepository.FindByExpression(t =>
(t.Teacher.Id == dto.TeacherId) &&
(t.Id != dto.Id) &&
(
(t.ExternalId != null && student.ExternalId != null
)

You should use an Expression<Func<T, bool>> instead of Func<T, bool>.

Related

How can I use Symfony with a SELECT inside a WHERE clause? I got error

I'm migrating Mysql SQL to Symfony project and I get a error from TLP when I execute the SQL. I guess problem is in the second SELECT inside the WHERE clause.
If I use the original SQL, and I use without symfony framework I have no problems. Furthermore, if I use the clause WHERE with "(vars.ns IN (SELECT...))" I get no errors, but SQL must not be like that.
date_default_timezone_set('UTC');
$em = $this->getContainer()->get('doctrine')->getManager();
$query = $em->createQuery("SELECT vars.dm, vars.ns, vars.mc, vars.ac, vars.sf, vars.cn, vars.mp, vars.ta, vars.mo, vars.mh, vars.pa, vars.sp, vars.so, vars.sh, vars.sn, vars.mm, vars.ms, vars.gs, vars.a1, vars.a2, vars.updated FROM BaseBundle:Vars vars WHERE (SELECT device.id FROM BaseBundle:Device device WHERE device.ns = vars.ns AND device.idUser IS NOT NULL AND device.idUser != '422' AND device.idUser != '819') AND vars.idDevice IS NOT NULL AND vars.updated > :time")->setParameter('time', date('Y-m-d H:i:s', strtotime('-31 days')));
$historics = $query->getResult();
And I get this error:
[Doctrine\ORM\Query\QueryException]
[Syntax Error] line 0, col 233: Error: Expected Literal, got 'SELECT'
This SQL must return 276 rows and it does, but not in symfony. Any idea about the issue?
Thank you so much,
UPDATE:
MYSQL ORIGINAL QUERY
SELECT
vars.dm,
vars.ns,
vars.mc,
vars.ac,
vars.sf,
vars.cn,
vars.mp,
vars.ta,
vars.mo,
vars.mh,
vars.pa,
vars.sp,
vars.so,
vars.sh,
vars.sn,
vars.mm,
vars.ms,
vars.gs,
vars.a1,
vars.a2,
vars.updated
FROM
table_3.vars
WHERE
(SELECT
device.id_user
FROM
table_3.device
WHERE
device.ns = vars.ns
AND device.id_user IS NOT NULL
AND device.id_user != '422'
AND device.id_user != '819')
AND vars.id_device IS NOT NULL
AND vars.updated > NOW() - INTERVAL 30 DAY
First of all Doctrine does not use SQL it uses DQL. DQL looks similar, but works a bit differently when you talk about properties and fields. While creating Doctrine Query you have to use property names rather than field names and entity which you are referring to must exist with such properties. Is your BaseBundle:Vars entity present? and does it have properties mentioned in query string? And how about device entity?
You get this error
Expected Literal, got 'SELECT'
because doctrine tries to parse the subquery condition:
(SELECT device.id FROM BaseBundle:Device device WHERE device.ns = vars.ns AND device.idUser IS NOT NULL AND device.idUser != '422' AND device.idUser != '819')
and expects it to be a Literal
That happens because no comparison has been defined for the above condition and doctrine assumes that this should be a literal and when "sees" that it starts with "SELECT", it throws the error.
To overcome this, add a comparison (eg > 0) to the condition:
(SELECT device.id FROM BaseBundle:Device device WHERE device.ns = vars.ns AND device.idUser IS NOT NULL AND device.idUser != '422' AND device.idUser != '819') > 0

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.

LINQ to SQL - nullable types in where clause

I have a table with a column that has null values... when I try to query for records where that column IS NULL:
THIS WORKS:
var list = from mt in db.MY_TABLE
where mt.PARENT_KEY == null
select new { mt.NAME };
THIS DOES NOT:
int? id = null;
var list = from mt in db.MY_TABLE
where mt.PARENT_KEY == id
select new { mt.NAME };
Why?
after some more googling, I found the answer:
ref #1
ref #2
int? id = null;
var list = from mt in db.MY_TABLE
where object.Equals(mt.PARENT_KEY, id) //use object.Equals for nullable field
select new { mt.NAME };
This LINQ renders to SQL as follows:
((mt.PARENT_KEY IS NULL) AND (#id IS NULL))
OR ((mt.PARENT_KEY IS NOT NULL) AND (#id IS NOT NULL) AND (mt.PARENT_KEY = #id))
One possibility - if mt.PARENT_KEY is of some other type (e.g. long?) then there will be conversions involved.
It would help if you could show the types involved and the query generated in each case.
EDIT: I think I have an idea...
It could be because SQL and C# have different ideas of what equality means when it comes to null. Try this:
where (mt.PARENT_KEY == id) || (mt.PARENT_KEY == null && id == null)
If this is the case then it's a pretty ugly corner case, but I can understand why it's done that way... if the generated SQL is just using
WHERE PARENT_KEY = #value
then that won't work when value is null - it needs:
WHERE (PARENT_KEY = #value) OR (PARENT_KEY IS NULL AND #value IS NULL)
which is what the latter LINQ query should generate.
Out of interest, why are you selecting with
select new { mt.NAME }
instead of just
select mt.NAME
?) Why would you want a sequence of anonymous types instead of a sequence of strings (or whatever type NAME is?
It's definitely a matter of C# and SQL having different notions of how to compare nulls - the question has been addressed here before:
Compare nullable types in Linq to Sql

Simple math question with LinQ, simple Join query, Nulls, etc

I have 2 tables
1. Client
2. Operations
Operations can result in: Credits or Debits ('C' or 'D' in a char field) along with date and ammount fields.
I must calculate the balance for each client's account using linQ... The result should also show balance 0 for clients whom didn't make operations yet
I have the following function with linQ statement, but I know it could be done in a better and quicker, shorter way, right? Which will be?
public static double getBalance(ref ClasesDeDatosDataContext xDC, string SSN,
int xidClient)
{
var cDebits =
from ops in xDC.Operations
where (ops.idClient == xidClient) && (ops.OperationCode == 'D')
select ops.Ammount;
var cCredits =
from ops in xDC.Operations
where (ops.idClient == xidClient) && (ops.OperationCode == 'C')
select ops.Ammount;
return (double)(cCredits.Sum() - cDebits.Sum());
}
Thanks !!!
I don't know if the LINQ-to-SQL engine can handle the expression, but something like this should be possible:
return (
from ops in xDC.Operations
where ops.idClient == xidClient
select ops.operationCode == 'C' ? ops.Amount : -ops.Amount
).Sum(a => a);
Or perhaps:
return (
from ops in xDC.Operations
where ops.idClient == xidClient
select new { Sign = ops.operationCode == 'C' ? 1.0 : -1.0, Amount = ops.Amount }
).Sum(o => o.Sign * o.Amount);
If the collection is empty, the Sum method returns zero, so that takes care of clients without transactions.
Edit:
Corrected spelling in query: Ampont -> Amount