I need to select only two columns from Hospital table, HospitalId and Name.
i tried the below code it selects all columns from Hospital table which lead to slow performance. Please help me to select only two columns from Hospital table
public HttpResponseMessage GetAvailableHospitalsByAjax(System.Guid? DirectorateOfHealthID = null, System.Guid? UnitTypeID = null, string DeviceTypeIDs = null)
{
Context db = new Context();
var query = db.Hospitals.AsQueryable();
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().Select(w => new HospitalInfo()
{
Id = w.ID,
Name = w.Name
}).ToList();
return Request.CreateResponse(HttpStatusCode.OK, list);
}
IQueryable<T> executes select query on server side with all filters. Hence does less work and becomes fast.
IEnumerable<T> executes select query on server side, load data in-memory on client side and then filter data. Hence does more work and becomes slow.
List<T> is just an output format, and while it implements IEnumerable<T>, is not directly related to querying.
So,
var list = query.ToList().Select(w => new HospitalInfo()
{
Id = w.ID,
Name = w.Name
}).ToList();
In your code you use query.ToList(). This means at first it pull all data into memory then apply Select query.If you want to retrieve HospitalID and Name then remove ToList() then your code like
var list = query.Select(w => new HospitalInfo
{
Id = w.ID,
Name = w.Name
}).ToList();
Remove the ToList call before the projection:
var list = query.Select(w => new HospitalInfo()
{
Id = w.ID,
Name = w.Name
}).ToList();
With that ToList call you are materializing your query before do the projection
Because you do query.ToList() this materialises the entire query with all columns into memory. It's actually a bad habit to get into. Instead, remove that, you already have it at the end anyway. The Select projection you have will only retrieve the relevant columns though:
var list = query.Select(w => new HospitalInfo()
{
Id = w.ID,
Name = w.Name
}).ToList();
Related
I have a problem trying to reuse some subqueries. I have the following situation:
var rooms = dbContext.Rooms.Select(r => new
{
RoomId = r.Id,
Zones = r.Zones.Select(zr => zr.Zone),
Name = r.Name,
Levels = r.Levels.Select(lr => lr.Level),
IdealSetpoint = (double?)r.Group.Setpoints.First(sp => sp.ClimaticZoneId == dbContext.ClimaticZonesLogs.OrderByDescending(cz => cz.Timestamp).First().ClimaticZoneId).Setpoint??int.MinValue,
Devices = r.Devices.Select(rd => rd.Device)
}).ToList();
var tagsTypes = rooms.Select(r => r.Devices.Select(d => GetSetpointTagTypeId(d.DeviceTypeId))).ToList().SelectMany(x => x).Distinct().ToList();
predicate = predicate.And(pv => tagsTypes.Contains(pv.TagSettings.TagTypeId) &&
pv.ClimaticZoneId == dbContext.ClimaticZonesLogs.OrderByDescending(cz => cz.Timestamp).First().ClimaticZoneId);
var setpoints = valuesSubquery.Include(t=>t.TagSettings).Where(predicate).ToList();
This works fine, and generates the exact queries as wanted. The problem is that I want to have this subquery dbContext.ClimaticZonesLogs.OrderByDescending(cz => cz.Timestamp).First().ClimaticZoneId to be taken from a method and not repeat it every time I need it.
I've tested it with the database, where I have values in the corresponding tables, and I've tested the query with the database without any data in the corresponding tables. It works fine with no problems or exceptions.
But when I try to extract the repeating subquery in a separate method and execute it against empty database tables (no data) the .First() statement throws error. Here is the code:
protected long GetClimaticZoneId()
{
return dbContext.ClimaticZonesLogs.OrderByDescending(cz => cz.Timestamp).First().ClimaticZoneId;
}
and the query generation:
var rooms = dbContext.Rooms.Select(r => new
{
RoomId = r.Id,
Zones = r.Zones.Select(zr => zr.Zone),
Name = r.Name,
Levels = r.Levels.Select(lr => lr.Level),
IdealSetpoint = (double?)r.Group.Setpoints.First(sp => sp.ClimaticZoneId == GetClimaticZoneId()).Setpoint??int.MinValue,
Devices = r.Devices.Select(rd => rd.Device)
}).ToList();
var tagsTypes = rooms.Select(r => r.Devices.Select(d => GetSetpointTagTypeId(d.DeviceTypeId))).ToList().SelectMany(x => x).Distinct().ToList();
predicate = predicate.And(pv => tagsTypes.Contains(pv.TagSettings.TagTypeId) &&
pv.ClimaticZoneId == GetClimaticZoneId());
var setpoints = valuesSubquery.Include(t=>t.TagSettings).Where(predicate).ToList();
After execution I get InvalidOperationException "Sequence do not contain any elements" exception in the GetClimaticZoneId method:
I'm sure that I'm not doing something right.
Please help!
Regards,
Julian
As #Gert Arnold suggested, I used the GetClimaticZoneId() method to make a separate call to the database, get the Id and use it in the other queries. I gust modified the query to not generate exception when there is no data in the corresponding table:
protected long GetClimaticZoneId()
{
return dbContext.ClimaticZonesLogs.OrderByDescending(cz => cz.Timestamp).FirstOrDefault()?.ClimaticZoneId??0;
}
I've got an api call getUser which returns ALL the info from the database at the specified column, but I want to exclude some things; phonenumber, email etc.
Tried fiddling with the LINQ, changeing the modelBuilder, changeing the optionBuilder
Have looked for any SQL saying "Select * from" but found nothing
Deleting things in my UserModel do work, however this is an ugly way of doing it.
Result<UserModel> result = new Result<UserModel>();
try
{
using (var db = new ComeatDBContext(optionsBuilder.Options))
{
var user = db.User
.Include(f => f.Nationality)
.Include(f => f.State)
.FirstOrDefault(e => e.Id == id && !e.IsDeleted);
result.ResponseObject = (new UserModel()).FromUser(user);
var house = db.House.FirstOrDefault(e => e.UserId == user.Id);
if (house != null)
{
result.ResponseObject.House = ( new HouseModel() ).FromHouse(house);
}
result.Success = true;
}
Expected specifying which data to include (or not include) but instead I get everything unless I set the values to "null" after they've been delievered by the DB.
The .FirstOrDefault(...) is what causes the underlying database query (SQL) to be executed. It will populate all properties that are defined on the entity. The data entity is then transformed to your UserModel object when you execute (new UserModel()).FromUser(user);.
If you want to reuse your UserModel class but not populate all the columns you can do something like this;
var userModel = db.User
.Select(x => new UserModel { Name = x.Name, Id = x.Id })
.FirstOrDefault(e => e.Id == id && !e.IsDeleted);
result.ResponseObject = userModel;
I am new to LINQ queries, please help me out to find the solution.
I have a source in Entity Framework data model, there is a table currency bound to the source with columns currencyID and CurrencyName.
I need to get the values from the database to the DataTable using a LINQ query.
I tried something like mentioned below but it's not working:
var dataset = Source.T_Currency
.Where(x=> x.CurrencyID == x.CurrencyID && x.CurrencySymbol == x.CurrencySymbol)
.Select(x => new x.Currency
{
CurrencyID = x.CurrencyID,
CurrencySymbol = x.CurrencySymbol
}).ToList();
If you want to select all rows from T_Currency then try
Source.T_Currency
.Select(x => new
{
x.CurrencyID,
x.CurrencySymbol
})
.ToList()
To filter result by any value add Where statement before Select:
Source.T_Currency
.Where(x => x.CurrencySymbol == myCurrency) // where myCurrency is variable/parameter
.Select(x => new
{
x.CurrencyID,
x.CurrencySymbol
})
.ToList()
It is example with Select statement but actually in this case it is not requied, so Source.T_Currency.ToLost() returns the same result as the first code snippet. Difference is in type of values but if you can use original class then you should not create anonimous type.
you should use LINQ Join like this example:
var custSupJoin =
from sup in suppliers
join cust in customers on sup.Country equals cust.Country
select new { Country = sup.Country, SupplierName = sup.SupplierName, CustomerName = cust.CompanyName };
I have two disparate datasources, one has details about Clients the other the Site that only has a ClientID but due to partial migration of a system I can't join them at a database level (yet, that will eventually happen!):
var clients = _clientService.GetClientSummary(true);
var results = context.Sites.AsNoTracking().OrderByDescending(s => s.Id).
Skip((pageIndex - 1) * pageSize).Take(pageSize);
result.Content = pageResult.Select(a => new QuoteSearch
{
Accepted = a.Accepted,
Created = a.Created,
Id = a.Id,
Customer = clients.Find(b => b.Id == a.ClientId).Name
}).ToList();
Running the code above returns an error
"LINQ to Entities does not recognize the method
'CertsAssured.Model.Client.ClientSummary
Find(System.Predicate`1[CertsAssured.Model.Client.ClientSummary])' "
I can write the code after this step to perform the task but would then have to save the ClientId in to my object to then iterate through. Is there a way of getting the info from the client list during the Select method?
Thanks
After the database filtering/paging is set up, you can use AsEnumerable to convert the IQueryable result to an in memory IEnumerable where you can do lookups against clients;
result.Content = pageResult
.AsEnumerable()
.Select(a => new QuoteSearch
{
Accepted = a.Accepted,
Created = a.Created,
Id = a.Id,
Customer = clients.Find(b => b.Id == a.ClientId).Name
}).ToList();
If there are many database fields and you don't want all of the fetched from the database, you can filter the fields on the IQueryable first, something like;
result.Content = pageResult
.Select(a => new // This filters in the database
{ // to an anonymous type
Accepted = a.Accepted,
Created = a.Created,
Id = a.Id,
ClientId = a.ClientId
})
.AsEnumerable() // Convert to an IEnumerable
.Select(a => new QuoteSearch // This is done in-memory
{ // generating the real type
Accepted = a.Accepted,
Created = a.Created,
Id = a.Id,
Customer = clients.Find(b => b.Id == a.ClientId).Name
}).ToList();
I have 2 tables. 1 has entity's, 1 per row. Another is simply a mapping table of my EntitiesID and EmployeeID. I am trying to write a LINQ method that returns all Entities from the First Table where the EntityID is in the mapping table that is filtered by the EmployeeID.
Simplified Table Structure Example
TaskTable: ID, Description, Status
TaskViewTable: ID, TaskID, EmployeeID
So I want to return all Rows from TaskTable where the ID is in a SubQuery results of TaskViewTable based on EmployeeID.
Any help on doing this in LINQ? I have a 1 to Many set up between the two tables as well. I know there are similar questions am maybe I'm dense but they didn't seem to apply completely to what I was asking.(e.g. Linq Return Filtered Children)
Sorry forgot to show what I have so far:
IQueryable<tblTask> tTask=context.GetTable<tblTask>();
return tTask.Where(t => t.tblTasksViews.Where(v => v.EmployeeID == empID))
It, however, does not like my wherewith an unkown method Where(?)
Something like this should do the trick:
var tasks = tTask.Where(t =>
tTaskView.Where(v => v.ID == empId).Select(v => v.TaskId).Contains(t.ID));
You could break up the above into two sections:
//1.) Get all task views for the employeeID and only select the mapped TaskId
var taskViews = tTaskView.Where(v => v.ID == empId).Select(v => v.TaskId); //taskViews = IEnumerable<int>
//2.) Then get all tasks from the filtered task ids
var tasks = tTask.Where(t => taskViews.Contains(t.ID));
UPDATE
//3.) Project filtered results into IEnumerable<Task>
return tasks.Select(t => new Task()
{
ID = t.ID,
ActionableID = t.ActionableID,
StatusID = t.StatusID,
TypeID = t.TypeID,
Description = t.Description
});
You can, of course, string everything into a nice one-liner:
public List<Task> GetTasks(int empId)
{
return tTask
.Where(t => tTaskView.Where(v => v.ID == empId).Select(v => v.TaskId).Contains(t.ID))
.Select(t => new Task()
{
ID = t.ID,
ActionableID = t.ActionableID,
StatusID = t.StatusID,
TypeID = t.TypeID,
Description = t.Description
}).ToList();
}
Try something like this:
var query =
from tt in TaskTable
join tvt in TaskViewTable on tt.ID equals tvt.TaskID into xs
where xs.Any(z => z.EmployeeID == empID)
select tt;