Convert c# foreach to Linq expression - c#

I have following code snippet in c# which is working fine
foreach (var customer in customers.OrderBy(x => x.CustomerId))
{
if (customer.CustomerId != customerId)
{
winningRate = Helper.Utility.WinningRate(settledCustomers, customer.CustomerId).Status;
numberOfBets = customers.Count(x => x.CustomerId == customer.CustomerId);
numberOfWinnings = customers.Count(x => x.CustomerId == customer.CustomerId && x.Win > 0);
averageBet = Helper.Utility.CustomerAverageBet(settledCustomers, customer.CustomerId);
}
var risky = Helper.Utility.CheckRiskyBet(winningRate, numberOfWinnings, numberOfBets, averageBet, customer.Stake, customer.Win);
customer.Status = risky.Status;
customer.Message = risky.Message;
customerId = customer.CustomerId;
}
return customers;
Now I want to convert above code into LINQ expression and for the same I have written following code which is not giving the same output as
var r = from c in customers
let winningRate1 = Helper.Utility.WinningRate(settledCustomers, c.CustomerId).Status
let numberOfBets1 = customers.Count(x => x.CustomerId == c.CustomerId)
let numberOfWinnings1 = customers.Count(x => x.CustomerId == c.CustomerId && x.Win > 0)
let averageBet1 = Helper.Utility.CustomerAverageBet(settledCustomers, c.CustomerId)
let risky1 = Helper.Utility.CheckRiskyBet(winningRate, numberOfWinnings, numberOfBets, averageBet, c.Stake, c.Win)
where c.CustomerId != customerId
orderby c.CustomerId
select new Customer
{
Status = risky1.Status,
Message = risky1.Message,
CustomerId = c.CustomerId
};

where c.CustomerId != customerId
This clearly is wrong because it reduces the number of times the loop runs.
Many let clauses and control flow in the loop can get ugly when converting to query expressions. A multi-statement lambda often is easier and gets you the same functional code benefits:
customers
.OrderBy(x => x.CustomerId)
.Select(c => {
if (customer.CustomerId != customerId)
{
winningRate = Helper.Utility.WinningRate(settledCustomers, customer.CustomerId).Status;
numberOfBets = customers.Count(x => x.CustomerId == customer.CustomerId);
numberOfWinnings = customers.Count(x => x.CustomerId == customer.CustomerId && x.Win > 0);
averageBet = Helper.Utility.CustomerAverageBet(settledCustomers, customer.CustomerId);
}
var risky = Helper.Utility.CheckRiskyBet(winningRate, numberOfWinnings, numberOfBets, averageBet, customer.Stake, customer.Win);
return new Customer
{
Status = risky.Status,
Message = risky.Message,
CustomerId = c.CustomerId
};
});
This code is just a sketch, it has some issues that you can easily fix. For examples I'm assigning to non-local variables. Your code did not explain what those are so I left them alone.

Related

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())),

Issues when group join 3 table

Please help me resolve this issue. I still can not understand how it throw exception "system.linq.systemcore_enumerabledebugview evaluation time out" when debuging
var mealDataDetail = ( _dbContext.Meal.Where(m => m.IsDeleted == 0 && m.UserId == userId).ToList()
.GroupJoin(_dbContext.MealImage.Where(i => i.IsDeleted == 0 && i.MealType == (int)mealType).ToList(), p => p.Id, r => r.MealId, (p, rs) => new { p, rs })
.GroupJoin(_dbContext.MealMenu.Where(i => i.IsDeleted == 0 && i.MealType == (int)mealType).ToList(), prs => prs.p.Id, c => c.MealId, (prs, cs) => new MealDataDetail
{
MealId = prs.p.Id,
MealData = new MealData
{
MealImages = prs.rs.Select(im => im.Image),
Description = prs.p.BreakfastDescription,
Time = prs.p.BreakfastTime,
TimeRequired = prs.p.BreakfastTimeRequired,
Appitite = prs.p.BreakfastAppetite,
Status = prs.p.BreakfastStatus == 1,
Calorie = prs.p.BreakfastCalorie,
},
}));
Was it supposed to be a single query?
Keep in mind that your .ToList() is executing the query at that moment.
Try removing the ToList() but I suggest you rewrite it once the database is getting a really monster query. Is better to have a procedure instead

How to Select new model list after GroupBy mothod in Linq?

I want select grouped rows to a new model list.this is my code:
List<Model_Bulk> q = (from a in db.Advertises
join c in db.Companies on a.AdvertiseCompanyID equals c.CompanyID
where a.AdvertiseActive == true
&& a.AdvertiseExpireDate.HasValue
&& a.AdvertiseExpireDate.Value > DateTime.Now
&& (a.AdvertiseObjectType == 1
|| a.AdvertiseObjectType == 2)
select c)
.GroupBy(a => a.CompanyID).Select(a => new Model_Bulk
{
CompanyEmail = a.CompanyContactInfo.Email,
CompanyID = a.CompanyID,
CompanyName = a.CompanyName,
Mobile = a.CompanyContactInfo.Cell,
UserEmail = a.User1.Email,
categories = a.ComapnyCategories
}).ToList();
After group by, i can not use Select and naturally this syntax error raised:
System.Linq.IGrouping' does not contain a definition for 'CompanyContactInfo' and no extension method 'CompanyContactInfo' accepting a first argument of type
System.Linq.IGrouping' could be found (are you missing a using directive or an assembly reference?)
If i try with SelectMany() method.but the result will repeated and groupby method not work properly:
List<Model_Bulk> q = (from a in db.Advertises
join c in db.Companies on a.AdvertiseCompanyID equals c.CompanyID
where a.AdvertiseActive == true
&& a.AdvertiseExpireDate.HasValue
&& a.AdvertiseExpireDate.Value > DateTime.Now
&& (a.AdvertiseObjectType == 1
|| a.AdvertiseObjectType == 2)
select c)
.GroupBy(a => a.CompanyID).SelectMany(a => a).Select(a => new Model_Bulk
{
CompanyEmail = a.CompanyContactInfo.Email,
CompanyID = a.CompanyID,
CompanyName = a.CompanyName,
Mobile = a.CompanyContactInfo.Cell,
UserEmail = a.User1.Email,
categories = a.ComapnyCategories
}).ToList();
Instead of .SelectMany(a => a) you can use .Select(g => g.First()).That will give you the first item of each group.
(from a in db.Advertises
join c in db.Companies on a.AdvertiseCompanyID equals c.CompanyID
where a.AdvertiseActive == true && a.AdvertiseExpireDate.HasValue && a.AdvertiseExpireDate.Value > DateTime.Now && (a.AdvertiseObjectType == 1 || a.AdvertiseObjectType == 2)
select c)
.GroupBy(a => a.CompanyID)
.Select(g => g.First())
.Select(a => new Model_Bulk
{
CompanyEmail = a.CompanyContactInfo.Email,
CompanyID = a.CompanyID,
CompanyName = a.CompanyName,
Mobile = a.CompanyContactInfo.Cell,
UserEmail = a.User1.Email,
categories = a.ComapnyCategories
}).ToList();
Note that this might not be supported, if that is the case add an AsEnumerable call before .Select(g => g.First())
You should understand that after you do GroupBy() in your LinQ expresstion you work with a group so in your example it will be good to write like this:
List<Model_Bulk> q =
(from a in db.Advertises join c in db.Companies on a.AdvertiseCompanyID equals c.CompanyID
where a.AdvertiseActive == true
&& a.AdvertiseExpireDate.HasValue
&& a.AdvertiseExpireDate.Value > DateTime.Now
&& (a.AdvertiseObjectType == 1 || a.AdvertiseObjectType == 2)
select c)
.GroupBy(a => a.CompanyID)
.Select(a => new Model_Bulk
{
CompanyEmail = a.First().CompanyContactInfo.Email,
CompanyID = a.Key, //Note this line, it's can be happened becouse of GroupBy()
CompanyName = a.First().CompanyName,
Mobile = a.First().CompanyContactInfo.Cell,
UserEmail = a.First().User1.Email,
categories = a.First().ComapnyCategories
}).ToList();
Instead you could try something like this, instead of mixing query expressions and methods... (using FirstOrDefault() in the where / select as necessary)
(from a in db.Advertises
join c in db.Companies on a.AdvertiseCompanyID equals c.CompanyID
group a by new { a.CompanyId } into resultsSet
where resultsSet.AdvertiseActive == true && resultsSet.AdvertiseExpireDate.HasValue && resultsSet.AdvertiseExpireDate.Value > DateTime.Now && (resultsSet.AdvertiseObjectType == 1 || resultsSet.AdvertiseObjectType == 2)
select new Model_Bulk
{
CompanyEmail = resultsSet.CompanyContactInfo.Email,
CompanyID = resultsSet.CompanyID,
CompanyName = resultsSet.CompanyName,
Mobile = resultsSet.CompanyContactInfo.Cell,
UserEmail = resultsSet.User1.Email,
categories = resultsSet.ComapnyCategories
}).ToList();

LINQ to Entities does not recognize the method

This is my Code where I am fetching data.
var list = (from u in _dbContext.Users
where u.IsActive
&& u.IsVisible
&& u.IsPuller.HasValue
&& u.IsPuller.Value
select new PartsPullerUsers
{
AvatarCroppedAbsolutePath = u.AvatarCroppedAbsolutePath,
Bio = u.Bio,
CreateDateTime = u.CreationDate,
Id = u.Id,
ModifieDateTime = u.LastModificationDate,
ReviewCount = u.ReviewsReceived.Count(review => review.IsActive && review.IsVisible),
UserName = u.UserName,
Locations = (from ul in _dbContext.UserLocationRelationships
join l in _dbContext.Locations on ul.LocationId equals l.Id
where ul.IsActive && ul.UserId == u.Id
select new PartsPullerLocation
{
LocationId = ul.LocationId,
Name = ul.Location.Name
}),
Rating = u.GetPullerRating()
});
Now Here is my Extension.
public static int GetPullerRating(this User source)
{
var reviewCount = source.ReviewsReceived.Count(r => r.IsActive && r.IsVisible);
if (reviewCount == 0)
return 0;
var totalSum = source.ReviewsReceived.Where(r => r.IsActive && r.IsVisible).Sum(r => r.Rating);
var averageRating = totalSum / reviewCount;
return averageRating;
}
I have check this Post LINQ to Entities does not recognize the method
And I come to know I need to use
public System.Linq.Expressions.Expression<Func<Row52.Data.Entities.User, int>> GetPullerRatingtest
But how ?
Thanks
You can use conditionals inside LINQ to Entity queries:
AverageRating = u.ReviewsReceived.Count(r => r.IsActive && r.IsVisible) > 0 ?
u.ReviewsReceived.Where(r => r.IsActive && r.IsVisible).Sum(r => r.Rating) /
u.ReviewsReceived.Count(r => r.IsActive && r.IsVisible)
: 0
This will be calculated by the server, and returned as part of your list. Although with 10 million rows like you said, I would do some serious filtering before executing this.
Code within LINQ (to Entities) query is executed within database, so you can't put random C# code there. So you should either use user.GetPullerRating() after it is retrieved or create a property if you don't want to do the calculation every time.
You can also do:
foreach (var u in list)
u.Rating = u.GetPullerRating()
By the way, why is it extension method.

Convert from query to method

How to convert following code to method operator:
var myOrders = from c in customers
where c.Field<string>("Region") == "WA"
from o in orders
where c.Field<string>("CustomerID") == o.Field<string>("CustomerID")
&& (DateTime)o["OrderDate"] >= cutoffDate
select new {
CustomerID = c.Field<string>("CustomerID"),
OrderID = o.Field<int>("OrderID")
};
---------or----------
var myOrders = from c in customers
where c.Region == "WA"
from o in orders
where c.CustomerID == o.CustomerID
&& o.OrderDate >= cutoffDate
select new {
CustomerID = c.CustomerID,
OrderID = o.OrderID
};
same code in object form
I'd actually rewrite this as a join - probably via intermediate variables:
var washingtonCustomers = customers.Where(c => c.Field<string>("Region") == "WA");
var recentOrders = orders.Where(o => (DateTime)o["OrderDate"] >= cutoffDate);
var query = washingtonCustomers.Join(recentOrders,
c => c.Field<string>("CustomerID"),
o => o.Field<string>("CustomerID"),
(c, o) => new {
CustomerID = c.Field<string>("CustomerID"),
OrderID = o.Field<int>("OrderID")
});
You can try with this code - based on IEnumerable<KeyValuePair<string, Int32>
public IEnumerable<KeyValuePair<string, Int32>> YourQuery(DateTime date, string code)
{
var result =
from c in customers
where c.Field<string>("Region") == code
from o in orders
where c.Field<string>("CustomerID") == o.Field<string>("CustomerID")
&& (DateTime)o["OrderDate"] >= date
select new
{
CustomerID = c.Field<string>("CustomerID"),
OrderID = o.Field<int>("OrderID")
};
return result;
}
Are you just wanting to use the functional Linq syntax instead of query syntax? That would look like:
var myOrders = customers
.Where(c => c.Region == "WA")
.SelectMany(c =>
orders
.Where(o => (o.CustomerID == c.CustomerID)
&& (o.OrderDate > cutoffDate))
.Select(o => new {
CustomerID = c.CustomerID,
OrderID = o.OrderID
})
);

Categories

Resources