The code I use to filter my objects is like:
var dynamicdataentrances = db.DynamicDataEntrances.OrderByDescending(d => d.ID)
.AsQueryable();
if (TypeID != null)
dynamicdataentrances =
dynamicdataentrances.Where(d => d.DetailPageID == TypeID).AsQueryable();
if (RegionID != null)
dynamicdataentrances =
dynamicdataentrances.Where(d => d.RegionID == RegionID).AsQueryable();
if (ShiftGroupID != null)
dynamicdataentrances =
dynamicdataentrances.Where(d => d.ShiftPlan.ShiftGroupID == ShiftGroupID)
.AsQueryable();
And it works without any problems. However, filtering the objects according to "Workflow State" doesn't work. The code for it is like:
foreach (var wfs in workflowstates)
{
if (Request[wfs.ID.ToString()] != wfs.ID.ToString())
dynamicdataentrances =
dynamicdataentrances.Where(d => d.WorkflowStateRelation.WorkflowStateID
!= wfs.ID).AsQueryable();
}
As you can figure out, I use checkboxes for filtering; If Workflow State's checkbox isn't checked, I get the objects whose Workflow State isn't equal to unchecked one. I debugged the lines, foreach and if blocks are working correct, but the query doesn't work accordingly, it keeps getting all the objects. Is this a bug or am I doing something wrong?
If I turn my object collection to List before the Workflow State filtering, it works correctly.
With List it works, because the objects are already in the memory and not equal ones are ruled out for every non-checked state.
However, with IQueryable the objects are on the database, and the query gets all the objects, because they aren't ruled out from the list on each step.
I got the solution with:
var unCheckedStates = new List<int>();
foreach (var wfs in workflowstates)
{
if (Request[wfs.ID.ToString()] != wfs.ID.ToString())
{
unCheckedStates.Add(wfs.ID);
}
}
dynamicdataentrances =
dynamicdataentrances.Where(d => !unCheckedStates
.Contains(d.WorkflowStateRelation.WorkflowStateID))
.AsQueryable();
Related
Working with LINQ for the first time in a while and trying to clean something up. I have the following statements:
var element = await _Entities.References
.Where(db => db.LoadId == request.LoadId && db.ReferenceCode == "123")
.OrderByDescending(rec => rec.Created).FirstOrDefaultAsync(cancellationToken);
if (element != null) {
dto.ElementValue = element.Value;
}
I'd like to condense this into a single statement if possible but I was having trouble getting just the value from the await method.
You could do something like this:
dto.ElementValue = (await _Entity.References
.Where(db => db.LoadId == request.LoadId && db.ReferenceCode == "123")
.OrderByDescending(rec => rec.Created)
.FirstOrDefaultAsync(cancellationToken))?.Value
?? dto.ElementValue;
Note that technically this changes the behaviour of the code. Previously, if the query doesn't return a result, the ElementValue property is not touched. With a one-liner, if the query doesn't return a result, the ElementValue getter and setter will both be called.
Also, if the query returns a result whose Value is null, the ElementValue property will be set to itself rather than null.
I have a database in Azure that I created from scratch (not using code first in EF) and made a column in one of my tables to represent an Enum from my C# classes.
The enum is
public enum ItemType
{
Build,
Stock,
Shell,
Parts,
[Display(Name="All Vehicles")]
AllTypesOfVehicles
}
I am trying to select certain records in an EF Linq Query by using this enum in the where clause. I simply cast the enum to its underlying int32 data type but it does not retrieve me the results I want.
var results = context.Items.Include(P => P.Manufacturer)
.Include(P => P.Category).Include(P => P.VehicleMake)
.Include(P => P.VehicleModel).Include(P => P.VehicleYear);
//Fetches specific type of item
if (TypeOfPart != StaticData.ItemType.AllTypesOfVehicles)
{
results.Where(P => P.Type == (int)TypeOfPart); //This does not work
}
else //fetches all vehicle types
{
results.Where(P => P.Type == 0 | P.Type == 1 | P.Type == 2);
}
Is this expected in EF? I know EF supports Enum from a code first approach but I don't see why this would cause a problem. I went into my Azure portal and wrote a manual query to see if I would get the results that I wanted and I did.
SELECT * FROM Items WHERE Type = 2
This yielded me only results that were of enum type "Shell". Even hardcoding the number 2 into the where clause in my EF query does not get me the results I want. I rechecked my code to make sure I wasn't overriding that where clause anywhere else and everything seems clean. Just to be sure I even called .ToList() right after the where clause but still got bad results.
I'm not quite sure what I'm missing here???
============Edit after first answer=======================
var results = context.Items.Include(P => P.Manufacturer)
.Include(P => P.Category).Include(P => P.VehicleMake)
.Include(P => P.VehicleModel).Include(P => P.VehicleYear);
//Fetches specific type of item
if (TypeOfPart != StaticData.ItemType.AllTypesOfVehicles)
{
var part = (int)TypeOfPart;
results.Where(P => P.Type == part);
List<Item> t = results.ToList();
}
else //fetches all vehicle types
{
results.Where(P => P.Type == 0 | P.Type == 1 | P.Type == 2);
}
You have to assign results.Where() back to results to get it work and try performing the cast outside EF query context:
//Fetches specific type of item
if (TypeOfPart != StaticData.ItemType.AllTypesOfVehicles)
{
var part = (int)TypeOfPart;
results = results.Where(P => P.Type == part ); //This does not work
}
else //fetches all vehicle types
{
results = results.Where(P => P.Type == 0 | P.Type == 1 | P.Type == 2);
}
And btw, should you just skip the P.Type related Where when you're trying to fetch all types of vehicles? It would mean you don't need else.
//Fetches specific type of item
if (TypeOfPart != StaticData.ItemType.AllTypesOfVehicles)
{
var part = (int)TypeOfPart;
results.Where(P => P.Type == part ); //This does not work
}
I am trying to filter some objects using linq to enitites and I get an error telling me "Enumeration yielded no results".
on the client side I get a message like this:
The operation cannot be completed because the DbContext has been
disposed
I know that these filter values should return some results but it just doesnt work, so Im guessing my query is wrong, can you help please.
var mediaChannels =
NeptuneUnitOfWork.MediaChannels
.FindWhere(m => m.CountryID == CountryID &&
m.SonarMediaTypeID == MediaTypeID &&
m.SonarMediaTypes.SonarMediaGroupID == MediaGroupID &&
m.Name.Contains(search))
.Select(m => new MediaChannelModel() {
ID = m.ID,
Name = m.Name,
MediaType = m.MediaType.Name,
Country = m.Countries.Name,
SubRegion = m.Countries.Lookup_SubRegions.Name,
Region = m.Countries.Lookup_SubRegions.Lookup_Regions.Name
});
My guess is that this runs just fine, then you dispose you context, then you try to access mediaChannels. The problem is that Linq uses deferred execution. Therefore, you query doesn't really execute until you enumerate mediaChannels, which is after you context is disposed.
If you don't want to use deferred execution, then add a .ToList() to the end of your query to force it to load right there.
If you want to use deferred execution, then you can't dispose of your context until a later point.
The operation cannot be completed because the DbContext has been disposed is often seen if you send data to the client without saving the data to memory. This can be easily fixed by .ToList()-ing your query before sending it to the page
var mediaChannels = NeptuneUnitOfWork.MediaChannels
.Where(m => m.CountryID == CountryID
&& m.SonarMediaTypeID == MediaTypeID &&
&& m.SonarMediaTypes.SonarMediaGroupID == MediaGroupID
&& m.Name.Contains(search))
.Select(m => new MediaChannelModel() {
ID = m.ID,
Name = m.Name,
MediaType = m.MediaType.Name,
Country = m.Countries.Name,
SubRegion = m.Countries.Lookup_SubRegions.Name,
Region = m.Countries.Lookup_SubRegions.Lookup_Regions.Name
}).ToList(); // <<-- NOTE this additional method
I am working on these lists to get an item that matches the selected item from the combobox.
private void InitializaMessageElement()
{
if (_selectedTransactionWsName != null)
{
get a transaction webservice name matching the selected item from the drop down here the output=TestWS which is correct
var getTranTypeWsName = TransactionTypeVModel
.GetAllTransactionTypes()
.FirstOrDefault(transTypes =>
transTypes.WsMethodName == _selectedTransactionWsName);
Loop the list of wsnames from the treenode list. Here it gives me all the node I have which is correct.
var wsNameList = MessageElementVModel
.GetAllTreeNodes().Select(ame =>
ame.Children).ToList();//. == getTranTypeWsName.WsMethodName);
find the getTranTypeWsName.WsMethodName in the wsNameList. Here is where I have the problem:
var msgElementList = wsNameList.Select(x => x.Where(ame => getTranTypeWsName != null && ame.Name == getTranTypeWsName.WsMethodName)).ToList();
my MsgElement list:
MsgElementObsList = new ObservableCollection<MessageElementViewModel>(msgElementList);
this.messageElements = _msgElementList;
NotifyPropertyChanged("MessageElements");
}
Here it is throwing the cast error. why is it not working? I am new to LINQ. thanks
As the error is trying to tell you, LINQ methods return special iterator types the implement IEnumerable<T>; they do not return List<T>.
This enables deferred execution.
Since the object isn't actually a List<T>, you can't cast it to a type that it isn't.
If you need a List<T>, you can either call ToList(), or skip LINQ entirely and use List<T>.ConvertAll(), which is like Select(), but does return List<T>.
Modify
MsgElementObsList = new ObservableCollection<MessageElementViewModel>((List<MessageElementViewModel>) msgElementList);
to
MsgElementObsList = new ObservableCollection<MessageElementViewModel>(msgElementList);
This is because although all lists are enumerable, all enumerables are not lists, and this one happens not to be one.
Also, your bool error has to do with returning true in the select. Here's the fixed code for that:
var msgElementList = wsNameList.Select(x =>
x.Where(ame => ame.Name == getTranTypeWsName.WsMethodName));
I was doing project in MVC3 with Entity framework. I have a LINQ query with foreach. Everything is fine. But when the data size goes up, i was facing performance issues. I dont have much experience with LINQ. So I couldn't fix my issue. Pls have a look at my code and provide a better suggestion for me.
Code
List<int> RouteIds = db.Cap.Where(asd => asd.Type == 3).Select(asd => asd.UserId).ToList();
var UsersWithRoutingId = (from route in db.RoutingListMembers
where RouteIds.Contains(route.RoutingListId.Value) && route.User.UserDeptId == Id
select
new RoutingWithUser
{
UserId = route.UserId,
RoutingId = route.RoutingListId
});
var ListRouteValue = (from cap in db.CareAllocationPercents
where cap.Type == 3
select new UserWithDeptId
{
Year = (from amt in db.CareAllocations where amt.CareItemId == cap.CareItemId select amt.Year).FirstOrDefault(),
UserId = cap.UserId,
UserDeptId = (from userdept in db.Users where userdept.Id == cap.UserId select userdept.UserDeptId).FirstOrDefault(),
});
List<UserWithDeptId> NewRouteList = new List<UserWithDeptId>();
ListRouteValue = ListRouteValue.Where(asd => asd.Year == Year);
foreach (var listdept in ListRouteValue)
{
foreach (var users in UsersWithRoutingId)
{
if (users.RoutingId == listdept.UserId)
{
UserWithDeptId UserwithRouteObj = new UserWithDeptId();
UserwithRouteObj.UserId = users.UserId;
UserwithRouteObj.Year = listdept.Year;
UserwithRouteObj.UserDeptId = db.Users.Where(asd => asd.Id == users.UserId).Select(asd => asd.UserDeptId).FirstOrDefault();
NewRouteList.Add(UserwithRouteObj);
}
}
}
NewRouteList = NewRouteList.Where(asd => asd.UserDeptId == Id).ToList();
Thanks,
You have to use join in first statement. Examples of how to do this are for example here: Joins in LINQ to SQL
I have some idea for you:
First:
Take care to complete your where close into your linq query to get just what you need to.
With Linq on collection, you can remove one foreach loop. I don't know the finality but, i've tryied to write something for you:
var UsersWithRoutingId = (from route in db.RoutingListMembers
where RouteIds.Contains(route.RoutingListId.Value) && route.User.UserDeptId == Id
select
new RoutingWithUser
{
UserId = route.UserId,
RoutingId = route.RoutingListId
});
var ListRouteValue = (from cap in db.CareAllocationPercents
where cap.Type == 3
select new UserWithDeptId
{
Year = (from amt in db.CareAllocations
where amt.CareItemId == cap.CareItemId && amt.Year == Year
select amt.Year).FirstOrDefault(),
UserId = cap.UserId,
UserDeptId = (from userdept in db.Users
where userdept.Id == cap.UserId && userdept.UserDeptId == Id
select userdept.UserDeptId).FirstOrDefault(),
});
List<UserWithDeptId> NewRouteList = new List<UserWithDeptId>();
foreach (var listdept in ListRouteValue)
{
var user = UsersWithRoutingId.Where(uwri => uwri.RoutingId == listdept.UserId).FirstOrDefault();
if (user != null)
{
NewRouteList.Add(new UserWithDeptId { UserId=user.UserId, Year=listdept.Year, UserDeptId=listdept.UserDeptId });
}
}
return NewRouteList
Is that right for you ?
(i don't poll the db.user table do get the UserDeptId for the NewRouteList assuming that the one in the listdept is the good one)
Second:
Take care of entity data loading, if you have tables with foreign key, take care to remove the lazy loading if you don't need the children of your table to be loaded at same time. Imagine the gain for multiple table with foreign key pointing to others.
Edit:
Here is a link that explain it:
http://msdn.microsoft.com/en-us/library/vstudio/dd456846%28v=vs.100%29.aspx