I want to order the result with multiple comparisons like (by paid users, updated date, created date).
var order = _vrepository.Details()
.Where(od => od.Order.Id != null
&& od.PlanName.ToLower().Contains("DP".ToLower())
&& od.Order.Status == true)
.OrderByDescending(od => od.ValidityTill)
.Select(ord => ord.Order.Id.Value);
The above one I am getting the paid users.
var updatedList = _repository.GetUsers()
.Where(c => c.UpdatedDate != null
&& fresh <= c.UpdatedDate)
.Select(c => c.Id);
This second query I am getting updated users.
var UsersListByCreatedDate = _repository.GetUsers()
.Where(c => fresh <= c.CreatedDate)
.Select(c => c.Id);
The third one is for get the users by created date. Then I am selecting the Id (an Integer)
lstId = order.ToList();
lstUpdatedUsersId = updatedList ToList();
lstCreatedDatewiseUsers = UsersListByCreatedDate.ToList();
To show the ordered list I did the following code:
Func<IQueryable<User>, IOrderedQueryable<User>> orderingFunc = query =>
{
if (order.Count() > 0)
return query.OrderByDescending(rslt => lstId .Contains(rslt.Id))
.ThenByDescending(rslt => lstUpdatedUsersId .Contains(rslt.Id))
.ThenByDescending(rslt => lstCreatedDatewiseUsers.Contains(rslt.Id));
else
return query.OrderByDescending(rslt => lstUpdatedUsersId .Contains(rslt.Id))
.ThenByDescending(rslt => rslt.UpdatedDate);
};
But I am getting result as One Paid user, some Created user and the date is before 3 years like wise. I want to get the exact order is as follows
Ordered User
Updated User
Created User
Please help me to solve this issue. Hope I will get correct result.
I have tried this snipepd of code according to your
public class Program
{
public static void Main()
{
var l1= new List<int>{1,2,3};
var l2= new List<int>{4,5,6};
var l3= new List<int>{7,8,9};
var testList = new List<Test>{new Test{Id=9,Name="test1"},new Test{Id=11,Name="test1"},new Test{Id=5,Name="test1"},new Test{Id=7,Name="test1"},new Test{Id=2,Name="test1"}};
var orderedList= testList.OrderByDescending(e=> l1.Contains(e.Id)).ThenByDescending(e=> l2.Contains(e.Id)).ThenByDescending(e=> l3.Contains(e.Id));
Console.WriteLine(string.Join("\t", orderedList.Select(e=> e.Id).Cast<int>().ToArray()));
// it prompts 2 5 9 7 11
}
}
public class Test{
public int Id{get; set;}
public string Name{get; set;}
}
and it works as you expected. Maybe I haven't understood what you are trying to achieve.
Maybe the function that you are using to sort items is in the wrong branch of the if statment, check for if (order.Count() > 0)
Related
I have the following classes:
public class Customer
{
public string CustomerId;
public string CustomerName;
public List<CustomerOrder> Orders;
}
public class CustomerOrder
{
public string OrderName;
public string Account;
public string PassFail;
}
What I am trying to do is I need to get only Customer records that have had zero PassFails = "F" for that account. So for example if I have CustomerId = 1 and two Orders for Account = "1000" one PassFail = "P" and one = "F". I don't want the Customer record in my result set. So I have the following so far:
//get accounts where any order failed
var failedAccounts = customers.SelectMany(s => s.Orders)
.Where(w => w.PassFail == "F")
.GroupBy(g => g.Account)
.Select(g => new
{
Account = g.Key
});
I am stuck at this point as I am trying to get my customers list where all orders have passed for the account. Hope this makes sense. I want to still keep the Order record as is I need to know if one of the orders did pass but at a later stage I need to filter out the Customer records. Thanks all
customers.Where(s => s.Orders.All(o => o.PassFails == "F"))
and then add anything you want
customers.SelectMany() in the sample code is selecting all the Orders from the customers (but not the customers themselves). We can use customers.Where() to select Customers, and then to filter on accounts that have any order whose PassFail value is "F", we can use the Any extension method (from System.Linq):
var failedAccounts = customers.Where(s => s.Orders.Any(o => o.PassFails == "F"));
Conversly, if we want to find the customers whose orders are all passed, we can use All:
var passedAccounts = customers.Where(s => s.Orders.All(o => o.PassFails == "P"));
I have the AssessmentItems DB object which contains the items about: Which user evaluated (EvaluatorId), which submission (SubmissionId), based on which rubric item (or criteria)(RubricItemId) and when (DateCreated).
I group by this object by RubricItemId and DateCreated to get compute some daily statistics based on each assessment criteria (or rubric item).
For example, I compute the AverageScore, which works fine and returns an output like: RubricItem: 1, Day: 15/01/2019, AverageScore: 3.2.
_context.AssessmentItems
.Include(ai => ai.RubricItem)
.Include(ai => ai.Assessment)
.Where(ai => ai.RubricItem.RubricId == rubricId && ai.Assessment.Submission.ReviewRoundId == reviewRoundId)
.Select(ai => new
{
ai.Id,
DateCreated = ai.DateCreated.ToShortDateString(),//.ToString(#"yyyy-MM-dd"),
ai.CurrentScore,
ai.RubricItemId,
ai.Assessment.SubmissionId,
ai.Assessment.EvaluatorId
})
.GroupBy(ai => new { ai.RubricItemId, ai.DateCreated })
.Select(g => new
{
g.Key.RubricItemId,
g.Key.DateCreated,
AverageScore = g.Average(ai => ai.CurrentScore),
NumberOfStudentsEvaluating = g.Select(ai => ai.EvaluatorId).Distinct().Count(),
}).ToList();
What I want to do is to compute the average until that day. I mean instead of calculating the average for the day, I want to get the average until that day (that is, I want to consider the assessment scores of the preceding days). The same why, when I compute NumberOfStudentsEvaluating, I want to indicate the total number of students participated in the evaluation until that day.
One approach to achieve this could be to iterate through the result object and compute these properties again:
foreach (var i in result)
{
i.AverageScore = result.Where(r => r.DateCreated <= i.DateCreated).Select(r => r.AverageScore).Average(),
}
But, this is quite costly. I wonder if it is possible to tweak the code a bit to achieve this, or should I start from scratch with another approach.
If you split the query into two halves, you can compute the average as you would like (I also computed the NumberOfStudentsEvaluating on the same criteria) but I am not sure if EF/EF Core will be able to translate to SQL:
var base1 = _context.AssessmentItems
.Include(ai => ai.RubricItem)
.Include(ai => ai.Assessment)
.Where(ai => ai.RubricItem.RubricId == rubricId && ai.Assessment.Submission.ReviewRoundId == reviewRoundId)
.Select(ai => new {
ai.Id,
ai.DateCreated,
ai.CurrentScore,
ai.RubricItemId,
ai.Assessment.SubmissionId,
ai.Assessment.EvaluatorId
})
.GroupBy(ai => ai.RubricItemId);
var ans1 = base1
.SelectMany(rig => rig.Select(ai => ai.DateCreated).Distinct().Select(DateCreated => new { RubricItemId = rig.Key, DateCreated, Items = rig.Where(b => b.DateCreated <= DateCreated) }))
.Select(g => new {
g.RubricItemId,
DateCreated = g.DateCreated.ToShortDateString(), //.ToString(#"yyyy-MM-dd"),
AverageScore = g.Items.Average(ai => ai.CurrentScore),
NumberOfStudentsEvaluating = g.Items.Select(ai => ai.EvaluatorId).Distinct().Count(),
}).ToList();
Good evening guys. I'm currently developing a web application with the use of asp.net mvc and C# and I'm having trouble with using the groupby() and sum(). I'm attaching a screenshot of the output to better understand the situation i'm in.
what I want to do here is to group all with the same description and the total is to be summed. I have tried groupby and sum but i cant seem to arrive at the desired output. Can anyone please give me some good points on how to do this?
here is the codes i have tried in the manager:
public IEnumerable<TuitionFeeRevenuePerProgramVM_L> getDetails(string orgUnit, short? academicYear, byte? academicPeriod)
{
var depts = getAllOrgUnitDepByOrgUnitSchID(orgUnit);
var revenue = tuitionFee.SearchFor(x => x.AcademicPeriod == academicPeriod && x.AcademicYear == academicYear && depts.Contains(x.Course.OrgUnitCode) && x.IsLatest == true, "AssessmentItem.ChartOfAccount,AssessmentItem.ChartOfAccount.CostCenter,Course,Course.CourseSchedule,Course.OrgUnit,Course.OrgUnit.OrgUnitHierarchy1,Course.OrgUnit.OrgUnitHierarchy1.OrgUnit").ToList();
var r = revenue.GroupBy(x => x.Course.OrgUnitCode).Select(x => x.First()).ToList(); //this line seems to group them but the output is the first total amount not the overall total
var rev = revenue.Select(x => new TuitionFeeRevenuePerProgramVM_L
{
CostCenterCode = x.AssessmentItem.ChartOfAccount.CostCenterID,
CostCenterDesc = x.Course.OrgUnit.OrgUnitDesc,
Subjects = getNumberOfSubjects(x.Course.OrgUnitCode, x.AcademicYear, x.AcademicPeriod),
Enrolees = revenue.Where(y => y.Course.OrgUnitCode == x.Course.OrgUnitCode).Select(z => z.Course.CourseSchedule.Sum(a => a.EnrolledStudents)).Sum(b => b.Value),//(int)x.Course.CourseSchedule.Sum(y => y.EnrolledStudents),
Total = (decimal)((x.Course.CourseSchedule.Sum(y => y.EnrolledStudents) * x.Amount) * x.Course.ContactHrs) /*(revenue.Where(y => y.Course.OrgUnitCode == x.Course.OrgUnitCode).Select(z => z.Course.CourseSchedule.Sum(a => a.EnrolledStudents)).Sum(b => b.Value) * revenue.Where(d => d.Course.OrgUnitCode == x.Course.OrgUnitCode).Sum(e=>e.Amount)) * revenue.Where(f => f.Course.OrgUnitCode == x.Course.OrgUnitCode).Sum(g=>g.Course.ContactHrs) //*/
});
return rev.ToList();
}
the controller,model and view is as is since all the logic involved will be placed in the manager. I have tried to use Sum() when returning but it gets an error since the controller receives a list and not a decimal.
from d in data
group d by d.Description into g
from gg in g
select new {Description = gg.Key, Sum = gg.Sum(ggg=>ggg.TotalCost)}
Something like that without seeing the data class
function for get list of documents name only with distinct...
public static List<DocumentTypeModel> GetUploadedDocumentsName(int TicketId)
{
List<DocumentTypeModel> documents = new List<DocumentTypeModel>();
using (var db = new UnitOfWork())
{
documents = db.tbl_TrnTicketDocument.Get(x => x.FK_TicketId == TicketId && x.IsActive == true).Select(s => new DocumentTypeModel()
{
DocumentTypeNameEnglish = s.tbl_MstDocumentType.DocumentTypeNameEnglish
}).Distinct().ToList();
}
return documents;
}
currently result is this -
Affidavit in Case of Cancelled Will/No Will
Affidavit in Case of Cancelled Will/No Will
Allotment Letter
Allotment Letter
Death Certificate
Death Certificate
Lease Deed
Lease Deed
Photo Identity of Applicant
Photo Identity of Applicant
Possession Letter
Possession Letter
Registered/Unregistered Will
Registered/Unregistered Will
You can use groupby and select first option like this:
List<DocumentTypeModel> documents = new List<DocumentTypeModel>();
using (var db = new UnitOfWork())
{
documents = db.tbl_TrnTicketDocument.Get(x => x.FK_TicketId == TicketId && x.IsActive == true).Select(s => new DocumentTypeModel()
{
DocumentTypeNameEnglish = s.tbl_MstDocumentType.DocumentTypeNameEnglish
}).ToList();
documents = documents.GroupBy(x => x.DocumentTypeNameEnglish).Select(g => g.First());
}
Distinct() doesn't work like you tried on objects. Use IComparer to get this working https://support.microsoft.com/en-us/kb/320727
Create a comparer class
public class DocumentTypeModelComparer: IComparer
{
int IComparer.Compare(object a, object b)
{
if(a.Id == b.ID)
return 0;
else
return 1;
}
}
Now in your lambda expression
documents = db.tbl_TrnTicketDocument.Get(x => x.FK_TicketId == TicketId && x.IsActive == true).Select(s => new DocumentTypeModel()
{
DocumentTypeNameEnglish = s.tbl_MstDocumentType.DocumentTypeNameEnglish
}).ToList().Distinct(new DocumentTypeModelComparer()).ToList();
You are selecting the documenttypemodel and this is the distinct part (so all fields are checked), you probably want the distinct by via https://github.com/morelinq/MoreLINQ, or you can use group by with first see(linq distinct or group by multiple properties).
The other option is to select only the DocumentTypeNameEnglish field and you will get the unique documents.
documents = db.tbl_TrnTicketDocument.Get(x => x.FK_TicketId == TicketId && x.IsActive == true).Select(s => new { documentTypes =s.tbl_MstDocumentType.DocumentTypeNameEnglish}).Distinct().ToList();
Hopefully this is what you want, if not can you post more details?
https://social.msdn.microsoft.com/Forums/en-US/6303da53-c412-4ce6-a983-bd6bd87f516b/how-to-do-a-select-distinct-with-ef?forum=adodotnetentityframework
Kindly refer this link Its useful to you
Switch to the below per Vladimir's comment:
.ToList().Distinct();
I have a database with the table that keeps user_ids and tag_ids. I want to write a function which takes two user_ids and returns the tag_ids that both users have in common.
These are the sample rows from the database:
User_id Tag_id
1 100
1 101
2 100
3 100
3 101
3 102
What I want from my function is that when I call my function like getCommonTagIDs(1, 3), it should return (100,101). What I did so far is that I keep the rows which are related to user_id in two different lists and then using for loops, return the common tag_ids.
using (TwitterDataContext database = TwitterDataContext.CreateTwitterDataContextWithNoLock())
{
IEnumerable<Usr_Tag> tags_1 = database.Usr_Tags.Where(u => u.User_id == userID1).ToList();
IEnumerable<Usr_Tag> tags_2 = database.Usr_Tags.Where(u => u.User_id == userID2).ToList();
foreach (var x in tags_1)
{
foreach (var y in tags_2) {
if (x.Tag_id == y.Tag_id) {
var a =database.Hashtags.Where(u => u.Tag_id==x.Tag_id).SingleOrDefault();
Console.WriteLine(a.Tag_val);
}
}
}
}
What I want to ask is that, instead of getting all rows from database and searching for the common tag_ids in the function, I want to get the common tag_ids directly from database with LINQ by making the calculations on the database side. I would be grateful if you could help me.
This is the SQL that I wrote:
SELECT [Tag_id]
FROM [BitirME].[dbo].[User_Tag]
WHERE USER_ID = '1' AND Tag_id IN (
SELECT [Tag_id]
FROM [BitirME].[dbo].[User_Tag]
where USER_ID = '3')
What you want is the "Intersection" of those two sets:
var commonTags = database.Usr_Tags.Where(u => u.User_id == userID1).Select(u => u.Tag_id)
.Intersect(database.Usr_Tags.Where(u => u.User_id == userID2).Select(u => u.Tag_id));
And voila, you're done.
Or, to clean it up a bit:
public static IQueryable<int> GetUserTags(int userId)
{
return database.Usr_Tags
.Where(u => u.User_id == userId)
.Select(u => u.Tag_id);
}
var commonTags = GetUserTags(userID1).Intersect(GetUserTags(userID2));
Here's one way to do it:
int[] users = new int[] {1,3}; // for testing
database.Ustr_Tags.Where(t => users.Contains(t.User_id))
.GroupBy(t => t.Tag_id)
.Where(g => users.All(u => g.Any(gg=>gg.User_id == u))) // all tags where all required users are tagged
.Select(g => g.Key);
One benefit of this one is it can be used for any number of users (not just 2).
If i got it right, query like this is maybe what you need
var q = from t in database.Usr_Tags
//all Usr_Tags for UserID1
where t.User_Id == userID1 &&
//and there is a User_tag for User_ID2 with same Tag_ID
database.User_Tags.Any(t2=>t2.User_ID==userID2 && t2.Tag_ID==t.Tag_ID)
select t.Tag_Id;
var commonTags = q.ToList();