LINQ: How Can I Use Equals in query - c#

I need to use Equals method or something similar instead of using Contains method because i want to search in database for the exact values in selectedDeviceTypeIDs array not any of it.
IEnumerable<Guid> selectedDeviceTypeIDs = DeviceTypeIDs
.Split(',')
.Select( Guid.Parse )
.AsEnumerable();
query = query
.Where( j =>
j.HospitalDepartments.Any( jj =>
jj.Units.Any( m =>
m.Devices.Any( w =>
selectedDeviceTypeIDs.Contains( w.DeviceTypeID )
)
)
)
);
Here is my full code:
public HttpResponseMessage GetAvailableHospitalsByAjax(System.Guid? DirectorateOfHealthID = null, System.Guid? UnitTypeID = null, string DeviceTypeIDs = null)
{
Context db = new Context();
var query = db.Hospitals.AsQueryable();
if (DeviceTypeIDs != null)
{
IEnumerable<Guid> selectedDeviceTypeIDs = DeviceTypeIDs.Split(',').Select(Guid.Parse).AsEnumerable();
query = query.Where(j => j.HospitalDepartments.Any(jj => jj.Units.Any(m => m.Devices.Any(w => selectedDeviceTypeIDs.Contains(w.DeviceTypeID)))));
}
if (UnitTypeID != null)
{
query = query.Where(j => j.HospitalDepartments.Any(www => www.Units.Any(u => u.UnitTypeID == UnitTypeID)));
}
if (DirectorateOfHealthID != null)
{
query = query.Where(h => h.DirectorateHealthID == DirectorateOfHealthID);
}
query = query.Where(j => j.HospitalDepartments.Any(u => u.Units.Any(d => d.Devices.Any(s => s.Status == Enums.DeviceStatus.Free)))
&& j.HospitalDepartments.Any(hd => hd.Units.Any(u => u.Beds.Any(b => b.Status == Enums.BedStatus.Free))));
var list = query.ToList();
return Request.CreateResponse(HttpStatusCode.OK, list);
}

EF6 supports the SQL IN operator if the foo in foo.Contains( ) is an IList<T>, for example, this Linq:
Int32[] desired = new Int32[] { 1, 2, 3, 4 };
IQueryable<Item> itemsQuery = db.Items.Where( item => desired.Contains( item.SomeValue ) );
...will be converted into this:
SELECT Item.* FROM Items WHERE SomeValue IN ( 1, 2, 3, 4 )
I'm not entirely certain on the specifics, but I think if you convert your selectedDeviceTypeIDs from IQueryable<Guid> to Guid[] (or at least IList<Guid>) then EF will also generate an IN query for you.

Related

Duplicated linq query

I have 2 almost identical linq queries and want to remove repeating code from it. The only difference is the extra property in the GroupBy depending on some true/false condition.
How can I conditionally group by in linq without repeating the code like below?
var allergensList = _context.RecipeAllergens
.Where(x => x.ParentId == Id && x.AllergenId != null)
.ToList();
var allergens = new List<AllergenInfo>();
if (isRecipe)
{
allergens = allergensList
.GroupBy(x => new { x.AllergenName, x.AllergenIcon, x.AllergenMaycontains })
.Select(a =>
{
var v = a.OrderBy(x => x.AllergenMaycontains).First();
return new AllergenInfo
{
AllergenName = v.AllergenName,
AllergenIcon = v.AllergenIcon,
AllergenMayContain = v.AllergenMaycontains ?? false
};
})
.ToList();
}
else
{
allergens = allergensList
.GroupBy(x => new { x.AllergenName, x.AllergenIcon })
.Select(a =>
{
var v = a.OrderBy(x => x.AllergenMaycontains).First();
return new AllergenInfo
{
AllergenName = v.AllergenName,
AllergenIcon = v.AllergenIcon,
AllergenMayContain = v.AllergenMaycontains ?? false
};
})
.ToList();
}
You can left grouping by x.AllergenMaycontains but under condition
allergens = allergensList
.GroupBy(x => new { x.AllergenName, x.AllergenIcon, AllergenMaycontains = isRecipe ? x.AllergenMaycontains : false })
.Select(a =>
{
var v = a.OrderBy(x => x.AllergenMaycontains).First();
return new AllergenInfo
{
AllergenName = v.AllergenName,
AllergenIcon = v.AllergenIcon,
AllergenMayContain = v.AllergenMaycontains ?? false
};
})
.ToList();

Aggregate of string on anonymous type

I want to concat multiple string value into single string with comma separated,i tried using aggregate function but it shows cannot convert string to how to fix this issue,
I tried below code
var res = (from e in WYNKContext.SurgeryAssigned.Where(x => x.CmpID == cmpid && x.IsCancelled == false)
select new
{
ID = e.SAID,
UIN = e.UIN,
SurgeryDate = e.SurgeryDate,
SurgeryID = e.SurgeryID,
Surgery = ((from st in WYNKContext.SurgeryTran.
Where(x => x.SurgeryID == e.SurgeryID)
select new
{
desc = icdmaster
.Where(x => x.ID ==
st.IcdSpecialityCode).Select(x =>
x.SpecialityDescription).FirstOrDefault(),
}).ToList()).Aggregate((a, b) => a.desc + "," + b.desc),
}).ToList();
I want Output like inside surgery property like = string1,string 2 ,etc....
without using aggregate i am getting as count in Surgery Property
var res = (from e in WYNKContext.SurgeryAssigned.Where(x => x.CmpID == cmpid && x.IsCancelled == false)
select new
{
ID = e.SAID,
UIN = e.UIN,
SurgeryDate = e.SurgeryDate,
SurgeryID = e.SurgeryID,
Surgery = (from st in WYNKContext.SurgeryTran.Where(x => x.SurgeryID == e.SurgeryID)
select new
{
icd = icdmaster.Where(x => x.ID == st.IcdSpecialityCode).Select(x => x.SpecialityDescription).FirstOrDefault(),
}).ToList(),
}).ToList();
also tried string join :
Surgery = string.Join(",", (from st in WYNKContext.SurgeryTran.Where(x => x.SurgeryID == e.SurgeryID)
select new
{
icd = icdmaster.Where(x => x.ID == st.IcdSpecialityCode).Select(x => x.SpecialityDescription).FirstOrDefault(),
}).ToList()),
but in output i am getting like this
Surgery ={ icd = CORNEA },{ icd = CATARACT/IOL }
can some one tell what i did wrong in string.join.....
The string class has a static method named Join, which takes in a collection of items and a string to join them with, which should work for you here.
If I'm reading your code correctly, it would look something like this:
Surgery = string.Join(",", WYNKContext.SurgeryTran
.Where(surgTran => surgTran.SurgeryID == e.SurgeryID)
.Select(surgTran => icdmaster
.Where(icd => icd.ID == surgTran.IcdSpecialityCode)
.Select(icd => icd.SpecialityDescription)
.FirstOrDefault())),

How to use the Exact array value instead of Contains [duplicate]

This question already has answers here:
LINQ equal instead of Contains
(3 answers)
Closed 5 years ago.
I need to use Equals method or something similar instead of using Contains method because i want to search in database for the exact values in selectedDeviceTypeIDs array not any of it.
IEnumerable<Guid> selectedDeviceTypeIDs = DeviceTypeIDs
.Split(',')
.Select( Guid.Parse )
.AsEnumerable();
query = query
.Where( j =>
j.HospitalDepartments.Any( jj =>
jj.Units.Any( m =>
m.Devices.Any( w =>
selectedDeviceTypeIDs.Contains( w.DeviceTypeID )
)
)
)
);
Here is my full code
public HttpResponseMessage GetAvailableHospitalsByAjax(System.Guid? DirectorateOfHealthID = null, System.Guid? UnitTypeID = null, string DeviceTypeIDs = null)
{
Context db = new Context();
var query = db.Hospitals.AsQueryable();
if (DeviceTypeIDs != null)
{
IEnumerable<Guid> selectedDeviceTypeIDs = DeviceTypeIDs.Split(',').Select(Guid.Parse).AsEnumerable();
query = query.Where(j => j.HospitalDepartments.Any(jj => jj.Units.Any(m => m.Devices.Any(w => selectedDeviceTypeIDs.Contains(w.DeviceTypeID)))));
}
if (UnitTypeID != null)
{
query = query.Where(j => j.HospitalDepartments.Any(www => www.Units.Any(u => u.UnitTypeID == UnitTypeID)));
}
if (DirectorateOfHealthID != null)
{
query = query.Where(h => h.DirectorateHealthID == DirectorateOfHealthID);
}
query = query.Where(j => j.HospitalDepartments.Any(u => u.Units.Any(d => d.Devices.Any(s => s.Status == Enums.DeviceStatus.Free)))
&& j.HospitalDepartments.Any(hd => hd.Units.Any(u => u.Beds.Any(b => b.Status == Enums.BedStatus.Free))));
var list = query.ToList();
return Request.CreateResponse(HttpStatusCode.OK, list);
}
Your problem is not Contains() but with the Any() method used in your query which will return true immediately after it finds a device whose DeviceTypeID is in the provided selectedDeviceTypeIDs list.
If you need to check if all the devices of a unit match all the items in the list, you could use:
query = query
.Where(j =>
j.HospitalDepartments.Any(jj =>
jj.Units.Any(m =>
m.Devices.All(
w => selectedDeviceTypeIDs.Contains(w.DeviceTypeID))
&&
selectedDeviceTypeIDs.All(
g => m.Devices.Select(d => d.DeviceTypeID).Contains(g))
)
)
);
Note that if you have duplicate items in the selectedDeviceTypeIDs but not in the Devices of the Unit, it will still return true.

Translating SQL to lambda with groupby

I'm trying to translate this sql statement
SELECT row, SUM(value) as VarSum, AVG(value) as VarAve, COUNT(value) as TotalCount
FROM MDNumeric
WHERE collectionid = 6 and varname in ('C3INEV1', 'C3INEVA2', 'C3INEVA3', 'C3INVA11', 'C3INVA17', 'C3INVA19')
GROUP BY row
into an EF 4 query using lambda expressions and am missing something.
I have:
sumvars = sv.staticvararraylist.Split(',');
var aavresult = _myIFR.MDNumerics
.Where(r => r.collectionid == _collid)
.Where(r => sumvars.Contains(r.varname))
.GroupBy(r1 =>r1.row)
.Select(rg =>
new
{
Row = rg.Key,
VarSum = rg.Sum(p => p.value),
VarAve = rg.Average(p => p.value),
TotalCount = rg.Count()
});
where the staticvararraylist has the string 'C3INEV1', 'C3INEVA2', 'C3INEVA3', 'C3INVA11', 'C3INVA17', 'C3INVA19' (without single quotes) and the _collid variable = 6.
While I'm getting the correct grouping, my sum, average, & count values aren't correct.
You didn't post your error message, but I suspect it's related to Contains. I've found that Any works just as well.
This should get you quite close:
var result =
from i in _myIFR.MDNumerics
where i.collectionid == _collid && sumvars.Any(v => i.varname == v)
group i by i.row into g
select new {
row = g.Key,
VarSum = g.Sum(p => p.value),
VarAve = g.Average(p => p.value),
TotalCount = g.Count()
};
Try this:
var aavresult = _myIFR.MDNumerics
.Where(r => r.collectionid == _collid && sumvars.Contains(r.varname))
.GroupBy(r1 =>r1.row,
(key,res) => new
{
Row = key,
VarSum = res.Sum(r1 => r1.value),
VarAve = res.Average(r1 => r1.value),
TotalCount = res.Count()
});

How to use LINQ with calculated properties in a single pass?

I'd like to make a LINQ query, extracting dynamic properties (calculated fields) of my entities in a single pass, without get the error "The specified type member 'EntityKey' is not supported in LINQ to Entities".
Here is the only working way I found, but I am sure there are better and more elegant methods:
var q = (from i in
(from x in context.Tickets
select new { x.OperatoreID, x.DataObiettivo })
group i by new { i.OperatoreID } into g
select new vmOperatoreDateObiettivo
{
OperatoreID = g.Key.OperatoreID,
NOperatore = "", // field value to be updated...
DataObiettivo = g.Max(d => d.DataObiettivo),
MinutiAllaScadenza = 0, // field to be updated...
Alert = "" // field value to be updated...
}).ToList();
// Here I update my fields with a second pass....
foreach (vmOperatoreDateObiettivo e in q)
{
string nome = context.Operatori
.Where(t => t.OperatoreID == e.OperatoreID)
.First().CognomeNomePuntato.ToString();
e.NOperatore = nome;
int minscad = context.Tickets
.Where(t => t.OperatoreID == e.OperatoreID).AsEnumerable().Min(a => a.MinutiAllaScadenza);
e.MinutiAllaScadenza = minscad;
string sev = context.Tickets
.Where(t => t.OperatoreID == e.OperatoreID).AsEnumerable().Min(a => a.Alert);
e.Alert = sev;
}
Thanks in advance!
Try adding a let clause to your query and define calculated field, like so:
var q = (from i in
(from x in context.Tickets
select new { x.OperatoreID, x.DataObiettivo })
group i by new { i.OperatoreID } into g
let nOperatore = context.Operatori
.Where(t => t.OperatoreID == e.OperatoreID)
.First().CognomeNomePuntato.ToString() &&
minutialla = context.Tickets
.Where(t => t.OperatoreID == e.OperatoreID)
.AsEnumerable().Min(a => a.MinutiAllaScadenza) &&
alert = context.Tickets
.Where(t => t.OperatoreID == e.OperatoreID)
.AsEnumerable().Min(a => a.Alert)
select new vmOperatoreDateObiettivo
{
OperatoreID = g.Key.OperatoreID,
NOperatore = nOperatore,
DataObiettivo = g.Max(d => d.DataObiettivo),
MinutiAllaScadenza = minutialla,
Alert = alert
}).ToList();

Categories

Resources