Dynamic linq not working - linq

I have a problem. I want to build a dynamic LINQ query like this:
var result = from li in datacTx.LIs
where
(((StartDate != null) && (StartDate.Date != DateTime.MinValue)) ? li.Available <= StartDate.Date : true) &&
(((EndDate != null) && (EndDate.Date != DateTime.MinValue)) ? li.Expire <= EndDate.Date : true)
select new
{
A,
B,
C,
D
};
Before calling this query I am intializing the StartDate and EndDate with:
StartDate = DateTime.MinValue;
EndDate = DateTime.MinValue;
The problem is that the branch of "if" is always wrong I never can get the "true" branch if the StartDate and EndDate are having MinValue.

Try using a simpler condition:
where ((StartDate == DateTime.MinValue || li.Available <= StartDate.Date) &&
(EndDate == DateTime.MinValue || li.Expire <= EndDate))
However, if I were to implement something like this, I would actually create the query dynamically:
var query = datacTx.LIs;
if(StartDate != DateTime.MinValue)
query = query.Where(li => li.Available <= StartDate.Date);
if(EndDate != DateTime.MinValue)
query = query.Where(li => li.Expire <= EndDate .Date);
var result = query.Select(x => new { A, B, C, D });

Related

Having trouble trying to order using linq

I am trying to order by start date(s.StartDate). Below is my code so far, my understanding is that I should be adding .orderby(s.StartDate) somewhere but I don't think I'm even taking the correct route now as I have tried many ways.
var query = from s in context.SessionSearch
where s.Children == 0 && s.IsPublic == isPublic
select s;
var query = from s in context.SessionSearch
where s.Children == 0 && s.IsPublic == isPublic
if (startDate != null)
{
query = query.Where(s => s.StartDate >= startDate && s.StartDate <= endDate);
}
You should be able to start with the "without startdate" option - you have a couple of options here - either declare the type of the query specifically:
IQueryable<SessionSearch> query = from s in context.SessionSearch
where s.Children == 0 && s.IsPublic == isPublic
order by s.StartDate
select s;
And then as you've tried, add the additional where clause to the query if there's a start date passed in:
query = query.Where(s => s.StartDate >= startDate && s.StartDate <= endDate);
This means that you would not be able to add further ordering via the ThenBy methods.
Alternatively, you can add the order by clause after you've finished adding the where clauses:
var query = from s in context.SessionSearch
where s.Children == 0 && s.IsPublic == isPublic
select s;
if (startDate != null) {
query = query.Where(s => s.StartDate >= startDate && s.StartDate <= endDate);
}
query = query.OrderBy(s => s.StartDate);
Props to JonSkeet for pointing these out.

linq combine results from two tables to one select new statment?

With the following query how to I change that I dont have two sets of fields in the select new I want the information going into one set of columns not having two and a type field to say if its a traineeevent or a cpd event ?
List<EmployeeCPDReportRecord> employeeCPDRecords = new List<EmployeeCPDReportRecord>();
string employeeName;
var q = from cpd in pamsEntities.EmployeeCPDs
from traineeEvent in pamsEntities.TrainingEventTrainees
join Employee e in pamsEntities.Employees on cpd.EmployeeID equals e.emp_no
join TrainingEventPart tEventPart in pamsEntities.TrainingEventParts on traineeEvent.TrainingEventPartId equals tEventPart.RecordId
where (cpd.EmployeeID == id) && (startDate >= cpd.StartDate && endDate <= cpd.EndDate) &&
(traineeEvent.EmployeeId == id)
&& (traineeEvent.TraineeStatus == 1 || traineeEvent.TraineeStatus == 2)
&& (tEventPart.CPDHours > 0 || tEventPart.CPDPoints > 0)
&& (cpd.CPDHours > 0 || cpd.CPDPoints > 0)
|| traineeEvent.StartDate >= startDate
|| traineeEvent.EndDate <= endDate
orderby cpd.StartDate
select new
{
surname = e.surname,
forname1 = e.forename1,
forname2 = e.forename2,
EmployeeID = cpd.EmployeeID,
StartDate = cpd.StartDate,
EndDate = cpd.EndDate,
CPDHours = cpd.CPDHours,
CPDPoints = cpd.CPDPoints,
Description = cpd.Description,
TrainingStartDate = tEventPart.StartDate,
TrainingEndDate = tEventPart.EndDate,
TrainingCPDHours = tEventPart.CPDHours,
TrainingCPDPoints = tEventPart.CPDPoints,
TrainingEventDescription = tEventPart.Description
};
if (q != null)
{
Array.ForEach(q.ToArray(), i =>
{
if (ContextBase.encryptionEnabled)
employeeName = ContextBase.Decrypt(i.surname) + ", " + ContextBase.Decrypt(i.forname1) + " " + ContextBase.Decrypt(i.forname2);
else
employeeName = i.surname + ", " + i.forname1 + " " + i.forname2;
if (i.TrainingStartDate != new DateTime(1900, 1, 1))
employeeCPDRecords.Add(new EmployeeCPDReportRecord(employeeName, Convert.ToDateTime(i.StartDate), Convert.ToDateTime(i.EndDate), Convert.ToDecimal(i.CPDHours), Convert.ToDecimal(i.CPDPoints), i.Description,i.t,i.EndDate,Convert.ToDecimal(i.CPDHours),Convert.ToDecimal(i.CPDPoints),i.Description,"L&D"));
else
employeeCPDRecords.Add(new EmployeeCPDReportRecord(employeeName, Convert.ToDateTime(i.StartDate), Convert.ToDateTime(i.EndDate), Convert.ToDecimal(i.CPDHours), Convert.ToDecimal(i.CPDPoints), i.Description, i.StartDate, i.EndDate, Convert.ToDecimal(i.CPDHours), Convert.ToDecimal(i.CPDPoints), i.Description, "Employee CPD"));
});
}
Use this code
List<EmployeeCPDReportRecord> employeeCPDRecords = new List<EmployeeCPDReportRecord>();
var q = ( from cpd in pamsEntities.EmployeeCPDs
from traineeEvent in pamsEntities.TrainingEventTrainees
join Employee e in pamsEntities.Employees on cpd.EmployeeID equals e.emp_no
join TrainingEventPart tEventPart in pamsEntities.TrainingEventParts on traineeEvent.TrainingEventPartId equals tEventPart.RecordId
where (cpd.EmployeeID == id) && (startDate >= cpd.StartDate && endDate <= cpd.EndDate) &&
(traineeEvent.EmployeeId == id)
&& (traineeEvent.TraineeStatus == 1 || traineeEvent.TraineeStatus == 2)
&& (tEventPart.CPDHours > 0 || tEventPart.CPDPoints > 0)
&& (cpd.CPDHours > 0 || cpd.CPDPoints > 0)
|| traineeEvent.StartDate >= startDate
|| traineeEvent.EndDate <= endDate
orderby cpd.StartDate
select new EmployeeCPDReportRecord
{
YourEmployeColumnName=(ContextBase.encryptionEnabled==true?ContextBase.Decrypt(e.surname) + ", " + ContextBase.Decrypt(e.forname1) + " " + ContextBase.Decrypt(e.forname2):e.surname + ", " + e.forname1 + " " + e.forname2),
YourEmployeeCPDColumnName=(i.TrainingStartDate !=new DateTime(1900, 1, 1)?"L&D":"Employee CPD")
surname = e.surname,
forname1 = e.forename1,
forname2 = e.forename2,
EmployeeID = cpd.EmployeeID,
StartDate = cpd.StartDate,
EndDate = cpd.EndDate,
CPDHours = cpd.CPDHours,
CPDPoints = cpd.CPDPoints,
Description = cpd.Description,
TrainingStartDate = tEventPart.StartDate,
TrainingEndDate = tEventPart.EndDate,
TrainingCPDHours = tEventPart.CPDHours,
TrainingCPDPoints = tEventPart.CPDPoints,
TrainingEventDescription = tEventPart.Description
}).ToList<EmployeeCPDReportRecord>();

Problems with Linq(join)

I am writting a query with linq(follow code bellow). I am looking for data from db.imovel and for each one bring a picture nested into db.fotoimovel. Keep in mind that I may have more than one picture for each db.imovel data.
The issue is when I run, it returns me all the pictures with the same db.imovel data in all of them.
It works for me if return the db.imovel data with just one(may be the first picture) from db.fotoimovel.
Code:
var retorno = (from c in db.fotoimovel
join p in db.imovel on c.idImovel equals p.idImovel
where p.MetragemImovel >= metragem1 && p.MetragemImovel <= metragem2 &&
p.StatusImovel == opcao &&
((String.IsNullOrEmpty(bairro)) || p.BairroImovel == bairro) &&
((imovel == null) || (p.TipoImovel == imovel)) &&
((carros == null) || (p.QtdVagaGaragemImovel == carros)) &&
((quartos == null) || (p.QtdQuartoImovel == quartos))
select new DadosImovel
{
Id = p.idImovel,
Titulo = p.TituloImovel,
Descricao = p.DescricaoImovel,
Foto = c.NomeFotoImovel,
TipoImovel = p.TipoImovel,
Endereco = p.EnderecoImovel,
Complemento = p.ComplementoImovel,
Bairro = p.BairroImovel,
Cidade = p.CidadeImovel,
Estado = p.EstadoImovel,
CEP = p.CEPImovel,
MetragemImovel = p.MetragemImovel,
QtdComodoImovel = p.QtdComodoImovel,
QtdQuartoImovel = p.QtdQuartoImovel,
QtdBanheiroImovel = p.QtdBanheiroImovel,
QtdVagaGaragemImovel = p.QtdVagaGaragemImovel,
QtdAndarImovel = p.QtdAndarImovel,
Status = p.StatusImovel,
Ativo = p.AtivoImovel
}).Distinct().ToList();

I cant make Linq compare geodistances?

Im getting the error:
'new GeoCoordinate(MyEntity.Lat, MyEntity.Lon).GetDistanceTo(14.4416616666667, 5.71794583333333)' is not supported in a 'Where' Mobile Services query expression.
From the following query:
GeoCoordinate mypos = new GeoCoordinate(MainPage.myEntity.Lat, MainPage.myEntity.Lon);
var items = await App.MobileService
.GetTable<MyEntity>()
.Where(MyEntity => MyEntity.Id != MainPage.myEntity.Id && MyEntity.IsSelected == MainPage.myEntity.IsSelected
&& (MyEntity.Lat != 0 && MyEntity.Lon != 0)
&& new GeoCoordinate(MyEntity.Lat, MyEntity.Lon).GetDistanceTo(mypos) <= 5000)
.Take(20)
.ToListAsync();
I'm trying to get 20 entities from a table that is not me and within 5 km of my position.
One thing you need to be aware is that the line expression is not executed locally. It's instead translated into a query string which is sent to the server - otherwise you'd be downloading a lot more data than you need (which you still can do, by the way). Given that, there's no way to translate the method GeoCoordinate.GetDistanceTo into something which can be sent over the wire.
There are some operations which are supported in the server, such as arithmetic (+, -, *, /), and you could potentially implement something similar to what you need. Something like the code below should work (haven't tried it yet). Notice that you'll need to do the conversion between distance in coordinates (lat / lon) and whatever unit is returned by the GetDistanceTo method.
GeoCoordinate mypos = new GeoCoordinate(MainPage.myEntity.Lat, MainPage.myEntity.Lon);
double maxDistance = 1;
var items = await App.MobileService
.GetTable<MyEntity>()
.Where(e => e.Id != MainPage.myEntity.Id &&
e.IsSelected == MainPage.myEntity.IsSelected &&
(e.Lat != 0 && e.Lon != 0) &&
( ((e.Lat - mypos.Lat) * (e.Lat - mypos.Lat) +
(e.Lon - mypos.Lon) * (e.Lon - mypos.Lon)) < maxDistance )
.Take(20)
.ToListAsync();
Or, another alternative as I mentioned before would be to simply not to filter by the distance on that call, and filter it afterwards. Something like the code below:
GeoCoordinate mypos = new GeoCoordinate(MainPage.myEntity.Lat, MainPage.myEntity.Lon);
List<MyEntity> items = new List<MyEntity>();
int skip = 0;
while (items.Count < 20) {
var temp = await App.MobileService
.GetTable<MyEntity>()
.Where(e => e.Id != MainPage.myEntity.Id &&
e.IsSelected == MainPage.myEntity.IsSelected &&
(e.Lat != 0 && e.Lon != 0)
.Skip(skip)
.Take(20)
.ToListAsync();
if (temp.Count == 0) break;
foreach (var item in temp)
{
if (new GeoCoordinate(item.Lat, item.Lon).GetDistanceTo(mypos) <= 5000)
{
items.Add(item);
}
}
}

Converting a Query to LINQ

How can I convert the following query in a Linq with Lambda ?
SELECT DISTINCT Registro, COUNT(Registro) as qnt
FROM XML_Relatorio
WHERE Arquivo = 'redenet.xml'
AND TipoErro <> 'Imovel Inserido'
AND TipoErro <> 'TI'
AND DataHora BETWEEN '01-01-2012' AND '02-01-2012'
GROUP BY Registro
ORDER BY Registro
I'm trying the following code, but I need some help to build the LINQ with Lambda
IQueryable<XML_Relatorio> quantidadeErro = db.XML_Relatorios
.Where(a => a.Arquivo == "redenet.xml"
&& a.TipoErro != "Imovel Inserido"
&& a.TipoErro != "TI");
Supposing the DataHora field is of Date or DateTime type.
// parse the strings to datetime
var start = DateTime.Parse("01-01-2012");
var end = DateTime.Parse("02-01-2012");
IQueryable<XML_Relatorio> quantidadeErro = db.XML_Relatorios
.Where(a => a.Arquivo == "redenet.xml"
&& a.TipoErro != "Imovel Inserido"
&& a.TipoErro != "TI"
// and compare them...
&& a.DataHora > start && a.DataHora < end);

Resources