issue using Linq Any clause in Predicatebuilder - asp.net-mvc-3

I am having an issue with the LinqKit predicatebuilder. I have used it in the past for simple queries and it has worked fine but I am now trying to use it with an Any clause in the statement and it seems to be giving me random results. Below is the code I am using to build the statement. Can anyone see what I am doing wrong? Is there a better and easier way to do what I want to do. I am using predicatebuilder right now because there is a very complex query I am building which could contain nested predicates and such and I have seen no other easy way to do this. I am using this with entity framework.
if (cqv.ComplexQuery.IncludeOnAll)
{
Includepredicate = PredicateBuilder.True<Customer>();
}
else
{
Includepredicate = PredicateBuilder.False<Customer>();
}
inner = PredicateBuilder.True<Customer>();
if (a.Include == true || a.Exclude == true)
{
productinner = PredicateBuilder.True<CustomerProduct>();
if (a.VersiondID != 0)
{
productinner = productinner.And(o => o.ProductTypeID == a.ProductType.ID && o.VersionID == a.VersiondID);
inner = inner.And(o => o.Products.Any(productinner.Compile()));
}
else
{
productinner = productinner.And(o => o.ProductTypeID == a.ProductType.ID);
inner = inner.And(o => o.Products.Any(productinner.Compile()));
}
if (cqv.ComplexQuery.IncludeOnAll)
{
Includepredicate = Includepredicate.And(inner.Expand());
}
else
{
Includepredicate = Includepredicate.Or(inner.Expand());
}
}
IncludedCustomers = UoW.Customers.AsExpandable().Where(Includepredicate).ToList();
//This second list does the exact query the first one should be doing so I could compare results. The reuslts are totally different. Not only are there more results using predicatebuilder but they seem random
List<Customer> test = UoW.Customers.Where(o => o.Products.Any(s => s.ProductTypeID == 1)).ToList();
I don't see any easy way to try to debug issue with predicate builder either. Does anyone know of a quick way to determine the SQL that gets created from this query?
EDIT ----------------------------------------------
So I have solved part of my issue but run into another one. the issue with the Any clause and random results was fixed by me setting in integer variable with the a.ProductType.ID and using that value in the clause. Once I did that I got the results I expected. Now my issue is that even though this works fine when 1 product is select if I select naymore than 1 instead of either looking for any customers that have both of these products or either of these products the results I gt is always just the customer with the last product I put a clause in for. I will put my updated code below
foreach (CustomerProductQueryProduct a in cqv.ComplexQuery.Products)
{
inner = PredicateBuilder.True<Customer>();
if (a.Include == true || a.Exclude == true)
{
value = a.ProductType.ID;
productinner = PredicateBuilder.True<CustomerProduct>();
if (a.VersiondID != 0)
{
productinner = productinner.And(s => s.ProductTypeID == value && s.VersionID == a.VersiondID);
inner = inner.And(o => o.Products.Any(productinner.Compile()));
}
else
{
productinner = productinner.And(s => s.ProductTypeID == value);
inner = inner.And(o => o.Products.Any(productinner.Compile()));
}
if (cqv.ComplexQuery.IncludeOnAll)
{
Includepredicate = Includepredicate.And(inner.Expand());
}
else
{
Includepredicate = Includepredicate.Or(inner.Expand());
}
}
}
IncludedCustomers = UoW.Customers.AsExpandable().Where(Includepredicate).ToList();
Is PredicateBuilder not able to handle multiple Any clauses?

I finally figured out that I need to make temporary variable inside of my for loop to hold the value. When you do that it somehow knows to resolve the value immediately and the predicates work.

Related

Retrieve single element from LINQ query

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.

Linq Query Always returns False and Failed to Fetch Data

I am consuming wcf service into angular js application. I wrote linq query to check user information . If the is not null then query should catch the information and return true otherwise its should return false . But the problem is its always returns false and catch values null
Here is the linq Query .
public bool CreateCurrentAccountCheck(Current_Account_Holder_Details current_Account_Details)
{
using (HalifaxDatabaseEntities context =new HalifaxDatabaseEntities())
{
var query = (from x in context.Current_Account_Holder_Details
where x.Account_Holder_First_Name == current_Account_Details.Account_Holder_First_Name && x.Account_Holder_Last_Name == current_Account_Details.Account_Holder_Last_Name
&& x.Account_Holder_DOB == current_Account_Details.Account_Holder_DOB && x.Account_Holder_House_No == current_Account_Details.Account_Holder_House_No
&& x.Account_Holder_Street_Name == current_Account_Details.Account_Holder_Street_Name && x.Account_Holder_Post_Code == current_Account_Details.Account_Holder_Post_Code
select x).FirstOrDefault();
if (query!=null)
{
return true;
}
else
{
return false;
}
}
}
Here is the screen shot on debugging Mode .
The problem is pretty clear that there is no matched record with the where clauses. Also, you want to check the record and you should check it with using an unique id instead of other required or not required fields. It is the exact way to apply it. You should have some kind of unique AccountDetailId or other name which applies unique info for the records.
var query = (from x in context.Current_Account_Holder_Details
where x.AccountDetailId == current_Account_Details.AccountDetailId
select x).FirstOrDefault();

LINQ to Entities does not recognize the method 'Boolean HasFlag(System.Enum)' method, and this method cannot be translated into a store expression

I have this service:
//seroiunoiweucroewr
///wercewrwerwerwer
//wcererewrwerwer
public List<UserRoleContract> GetRolePagesByUserId(long plngUserId, DisplayType displayType)
{
List<UserRoleContract> result = new List<UserRoleContract>();
using (CitiCallEntities context = new CitiCallEntities())
{
try
{
//var DisplayList = Utility.GetEnumDescriptions(typeof(DisplayType)).ToList();
//var selectValue = DisplayList.Where(i => i.Key == (byte) DisplayType.Windows).FirstOrDefault();
result = (from oUser in context.User
join oUserRole in context.UserRole on oUser.Id equals oUserRole.UserId
join oRoleRightsPage in context.RoleRightsPage.Where(i => i.IsActive == true)
on oUserRole.RoleId equals oRoleRightsPage.RoleId
join oApplicationPage in context.ApplicationPage.Where(i => i.IsActive == true)
on oRoleRightsPage.PageId equals oApplicationPage.Id
join oRole in context.Role on oUserRole.RoleId equals oRole.Id
join oEmployee in context.Employee on oUser.EmployeeId equals oEmployee.Id
join oSection in context.Section on oEmployee.SectionId equals oSection.Id
where oUser.IsActive == true && oUser.Id == plngUserId
&& oRole.IsActive == true && (((DisplayType)oRoleRightsPage.DisplayType).HasFlag(displayType))
//am getting error in has flag
// am having three display type web, windows and all
// how to overcome
select new UserRoleContract
{
UserId = oUser.Id,
RoleId = oRole.Id,
RoleName = oRole.RoleName,
PageID = oApplicationPage.Id,
PageName = oApplicationPage.PageName,
IsOPsCtrl = oRole.IsOPsCtrl,
ISOPsCtrlFor = oRole.OPsCtrlFor,
SectionId = oSection.Id,
DisplayType = oRoleRightsPage.DisplayType,
}).Distinct().ToList();
}
catch (Exception exception)
{
HandleExpcetion(exception);
//throw new CitiCallException(exception.Message);
}
}
return result;
}
I am getting Linq error in has flag conversion, how do I overcome this problem?
you are geeting error because HasFlag method is not paresent in database i.e. it might be part of language or local function in code which is not present in database.
So when query is translated it found this method is not available and that is the reason you are getting error.
one solution to avoid this error is
Brind all data from databae
Than filter than data, i.e. apply HasFlag method of it.
But this will bring all data and might decrease performance.
Example is
remove this line (((DisplayType)oRoleRightsPage.DisplayType).HasFlag(displayType) from your query
var list = querieddata //first fetch data without hasflag condition/method
.AsEnumerable() // Rest of the query in-process
.Where(oRoleRightsPage=> ((DisplayType)oRoleRightsPage.DisplayType).HasFlag(displayType))//apply condition here once fetching done
.ToList();
The HasFlag method has no equivalent in Linq to Entities which is why you get that error. You can get around it by using bitwise comparison instead of using HasFlag, for example this:
((DisplayType)oRoleRightsPage.DisplayType).HasFlag(displayType)
Becomes:
(oRoleRightsPage.DisplayType & displayType) > 0

(Linq & EF) Where MyType = (int)Enum does not work

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
}

How to write this LINQ with foreach in a better way

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

Resources