in a mvc project i am using this method. However, when the database getting bigger and bigger, it is being very slow . How can i solve that ?
private List<SelectListItem> getDates() {
var db = new _Entities();
var list = new List<SelectListItem>();
var date = db.Location
.GroupBy(k => EntityFunctions.TruncateTime(k.DateServer))
.ToList();
//var date = db.Location.Select(m => m.DateService).Distinct();
foreach (var x in date)
{
list.Add(
new SelectListItem
{
Value = x.FirstOrDefault().DateServer.Date.ToShortDateString(),
Text = x.FirstOrDefault().DateServer.ToShortDateString()
} );
}
return list;
}
You should not create a list and a loop but use the database:
return db.Location.GroupBy(k => EntityFunctions.TruncateTime(k.DateServer))
.Select(group => new { group, first = group.First() })
.Select(x => new SelectListItem {
Value = x.first.DateServer.Date.ToShortDateString(),
Text = x.first.DateServer.ToShortDateString()
})
.ToList();
Since you are grouping by date the text and the value are the same, so it could be simplified:
return db.Location.GroupBy(k => EntityFunctions.TruncateTime(k.DateServer))
.Select(g => new SelectListItem { Value = g.Key.ToShortDateString(), Value = g.Key.ToShortDateString() })
.ToList();
Related
I have a complex LINQ Query to extract Top students in my university. Here is the query :
var query = Db.Students.AsNoTracking().Where(...).AsQueryable();
var resultgroup = query.GroupBy(st => new
{
st.Student.CourseStudyId,
st.Student.EntranceTermId,
st.Student.StudyingModeId,
st.Student.StudyLevelId
}, (key, g) => new
{
CourseStudyId = key.CourseStudyId,
EntranceTermId = key.EntranceTermId,
StudyingModeId = key.StudyingModeId,
StudyLevelId = key.StudyLevelId,
list = g.OrderByDescending(x =>
x.StudentTermSummary.TotalAverageTillTerm).Take(topStudentNumber)
}).SelectMany(q => q.list).AsQueryable();
This Query give me top n students based on 4 parameters and on their TotalAverageTillTerm.
Now I want to add rownum for each group to simulate Total rank, for example Output is :
Now I want to Add TotalRank as rownumber like Sql. In the picture X1=1,X2=2,X3=3 and Y1=1,Y2=2,Y3=3
If I want to reduce problem. I only work on one group. Code Like this :
resultgroup = query.GroupBy(st => new
{
st.Student.StudyLevelId
}, st => st, (key, g) => new
{
StudyLevelId = key.StudyLevelId,
list = g.OrderByDescending(x =>
x.StudentTermSummary.TotalAverageTillTerm)
.Take(topStudentNumber)
}).SelectMany(q => q.list).AsQueryable();
list was a List of student but I see no sign of student having a rank property so I wrapped it into a annonimous type with rank.
var query = Db.Students.AsNoTracking().Where(...).AsEnumerable();
var resultgroup = query.GroupBy(st => new {
st.Student.CourseStudyId,
st.Student.EntranceTermId,
st.Student.StudyingModeId,
st.Student.StudyLevelId
})
.SelectMany( g =>
g.OrderByDescending(x =>x.StudentTermSummary.TotalAverageTillTerm)
.Take(topStudentNumber)
.Select((x,i) => new {
CourseStudyId = g.Key.CourseStudyId,
EntranceTermId = g.Key.EntranceTermId,
StudyingModeId = g.Key.StudyingModeId,
StudyLevelId = g.Key.StudyLevelId,
Rank = i+1
//studentPorperty = x.Prop1,
})
)
.AsQueryable();
Do you mean :
var query = Db.Students.AsNoTracking().Where(...).AsQueryable();
var resultgroup = query.GroupBy(st => new
{
st.Student.CourseStudyId,
st.Student.EntranceTermId,
st.Student.StudyingModeId,
st.Student.StudyLevelId
}, (key, g) => new
{
CourseStudyId = key.CourseStudyId,
EntranceTermId = key.EntranceTermId,
StudyingModeId = key.StudyingModeId,
StudyLevelId = key.StudyLevelId,
list = g.OrderByDescending(x =>
x.StudentTermSummary.TotalAverageTillTerm)
.Take(topStudentNumber)
.Select((x, i) => new { Item = x, TotalRank = i /* item number inside group */}),
StudentsInGroupCount = g.Count() // count group this items
}).SelectMany(q => q).AsQueryable();
To see the results :
foreach (var item in resultgroup.ToList())
{
item.list.ForEach(s => Console.WriteLine(s.TotalRank));
}
How do I create groups and subgroup1 and subgroup2 Use linq.
Example of this picture
I want to create json.
Example of this picture.
I tried to do this but there was a problem.
The items are repeated within one subgroup2.
var list = result
.GroupBy(x => new { x.GroupId, x.GroupName })
.Select(g => new
{
ID = g.Key.GroupId,
Name = g.Key.GroupName,
SubGroup1 = g.GroupBy(x => new { x.SubGroupID1, x.SubGroupName1 })
.Select(cg => new
{
ID = cg.Key.SubGroupID1,
Name = cg.Key.SubGroupName1,
SubGroup2 = g.GroupBy(x => new { x.SubGroupID2, x.SubGroupName2 })
.Select(ii => new
{
ID = ii.Key.SubGroupID2,
Name = ii.Key.SubGroupName2,
item = ii.GroupBy(x => new { x.Stock_Id, x.Stock_Name, x.Prices, x.ScreenNumber })
.Select(oo => new
{
Stock_Id = oo.Key.Stock_Id,
Stock_Name = oo.Key.Stock_Name,
Prices = oo.Key.Prices,
ScreenNumber = oo.Key.ScreenNumber
}).OrderBy(Or => Or.Stock_Id)
.ToList()
}).OrderBy(Or => Or.ID)
.ToList()
}).OrderBy(Or => Or.ID)
.ToList()
}).OrderBy(Or => Or.ID)
.ToList();
Your query could be a lot cleaner if you grouped the groups up front, then project out to your desired results.
var query =
from x in data
group new { x.StockId, x.StockName, x.Prices, x.ScreenNumber }
by new { x.GroupId, x.GroupName, x.SubGroupId1, x.SubGroupName1, x.SubGroupId2, x.SubGroupName2 }
into g
group g
by new { g.Key.GroupId, g.Key.GroupName, g.Key.SubGroupId1, g.Key.SubGroupName1 }
into g2
group g2
by new { g2.Key.GroupId, g2.Key.GroupName }
into g1
select new
{
Id = g1.Key.GroupId,
Name = g1.Key.GroupName,
SubGroup1 = g1.Select(g2 => new
{
Id = g2.Key.SubGroupId1,
Name = g2.Key.SubGroupName1,
SubGroup2 = g2.Select(g => new
{
Id = g.Key.SubGroupId2,
Name = g.Key.SubGroupName2,
Items = g.Select(x => new
{
x.StockId,
x.StockName,
x.Prices,
x.ScreenNumber,
}),
}),
}),
};
The idea is to start off with the most specific grouping first, then one-by-one group the groups by the next layer, and so on.
SubGroup2 = g.GroupBy(x => new { x.SubGroupID2, x.SubGroupName2 })
You are grouping g instead of cg.
I suggest structuring your code a bit, which would help avoiding this kind of mistake.
I have this data
I would to convert Day to English value
for example :
"السبت" = "saturday"
"الاحد" = "sunday"
this code :
[HttpGet]
public JsonResult GetTime()
{
var data = _db.CourseTimes
.GroupBy(c => c.Day)
.ToDictionary(g => g.Key, v => v.Select(c => new { start = TimeSpan.FromHours(c.StartTime)
.ToString("hh':'mm"), stop = TimeSpan.FromHours(c.EndTime).ToString("hh':'mm") }));
return Json(data, JsonRequestBehavior.AllowGet);
}
return this :
{"الاحد":[{"start":"01:00","stop":"02:00"},{"start":"01:00","stop":"02:00"},{"start":"14:00","stop":"20:00"}],"السبت":[{"start":"01:00","stop":"02:00"},{"start":"05:00","stop":"08:00"},{"start":"07:00","stop":"06:00"}]}
I want it to return this:
OK, here is an implementation of how to do it:
[HttpGet]
public JsonResult GetTime()
{
var english_names = (new CultureInfo("en-US")).DateTimeFormat.DayNames
.Select((v, i) => new { Key = i, Value = v })
.ToDictionary(o => o.Key, o => o.Value);
var arabic_names = (new CultureInfo("ar-EG")).DateTimeFormat.DayNames
.Select((v, i) => new { Key = i, Value = v })
.ToDictionary(o => o.Key, o => o.Value);
var data = _db.CourseTimes
.GroupBy(c => c.Day)
.ToDictionary(g => english_names.FirstOrDefault(p => p.Key == arabic_names.FirstOrDefault(a => a.Value == g.Key).Key).Value, v => v.Select(c => new
{
start = TimeSpan.FromHours(c.StartTime).ToString("hh':'mm"),
stop = TimeSpan.FromHours(c.EndTime).ToString("hh':'mm")
}).ToList());
return Json(data, JsonRequestBehavior.AllowGet);
}
Basically, you just need to create two lists of names for each language and get the index of the english one for the arabic name, which is found on the second list.
try using CultureInfo, or you must mapping the word into table or static list, and compare that word...
The below code is used to create a dropdown list of services that my company offers. The services are being pulled from our database and I hard coded and added an additional item named "SSN Trace" to the list. The problem is that the item is still showing up at the end of the list instead of falling in alphabetical order with the rest of the list items. Can anyone help?
public List<SelectListItem> createProductsDropdownForTransReport()
{
var resultsOfProductsSearch = findAllByEnumSet(EnumLookup.EnumSetType.SterlingWestProducts);
var transanctionsReportProducts = resultsOfProductsSearch
.Where(el => el.Ordinal != 95 && el.Ordinal != 253)
.Select(el => new SelectListItem { Text = el.Text, Value = el.Text })
.OrderBy(el => el.Text)
.ToList();
transanctionsReportProducts.Add(new SelectListItem { Text = "SSN Trace", Value = "SSN Trace" });
var allTransReportProductsOption = new SelectListItem
{
Text = "All",
Value = String.Join(" | ", transanctionsReportProducts.Select(x => x.Text))
};
transanctionsReportProducts.Insert(0, allTransReportProductsOption);
transanctionsReportProducts.OrderBy(el => el.Text);
return transanctionsReportProducts;
}
CORRECT CODE:
public IEnumerable<SelectListItem> createProductsDropdownForTransReport()
{
var resultsOfProductsSearch = findAllByEnumSet(EnumLookup.EnumSetType.SterlingWestProducts);
var transanctionsReportProducts = resultsOfProductsSearch
.Where(el => el.Ordinal != 95 && el.Ordinal != 253)
.Select(el => new SelectListItem { Text = el.Text, Value = el.Text }).ToList();
transanctionsReportProducts.Add(new SelectListItem { Text = "SSN Trace", Value = "SSN Trace" });
transanctionsReportProducts = transanctionsReportProducts.OrderBy(el => el.Text).ToList();
var allTransReportProductsOption = new SelectListItem
{
Text = "All",
Value = String.Join(" | ", transanctionsReportProducts.Select(x => x.Text))
};
transanctionsReportProducts.Insert(0, allTransReportProductsOption);
return transanctionsReportProducts;
}
You are not doing anything on the return by OrderBy. You can immediately return the result of the OrderBy. When you call OrderBy, it doesn't mutate the existing list that you passed in. It creates a new list of the ordered elements and you are not doing anything on it.
More information can be found here
public IEnumerable<SelectListItem> createProductsDropdownForTransReport()
{
var resultsOfProductsSearch = findAllByEnumSet(
EnumLookup.EnumSetType.SterlingWestProducts);
var transanctionsReportProducts = resultsOfProductsSearch
.Where(el => el.Ordinal != 95 && el.Ordinal != 253)
.Select(el => new SelectListItem { Text = el.Text, Value = el.Text })
.OrderBy(el => el.Text)
.ToList();
transanctionsReportProducts.Add(new SelectListItem {
Text = "SSN Trace", Value = "SSN Trace" });
var allTransReportProductsOption = new SelectListItem
{
Text = "All",
Value = String.Join(" | ", transanctionsReportProducts.Select(x => x.Text))
};
transanctionsReportProducts.Insert(0, allTransReportProductsOption);
return transanctionsReportProducts.OrderBy(el => el.Text);
}
New to C# and appreciate any help. The issue is that I need to filter the results of my api call against an array (using an "allowedA" and "allowedB" array.) I don't know how to edit the lambda expression to check against the loop.
var activities = await _restClientTaxonomy.GetTaxonomyFullAsync(TAXONOMY_CLASSIFICATIONID_FOR_ACTIVITY);
var activityTypes = await _restClientTaxonomy.GetTaxonomyFullAsync(TAXONOMY_CLASSIFICATIONID_FOR_ACTIVITY_TYPES);
var documentEventxx = activities.Select(type => type.Id);
long [] allowedA = new long []{ 7137, 40385637};
long [] allowedB = new long []{ 7137, 40385637};
foreach (long value in documentEventxx)
{
foreach (var item in allowed)
{
if (item == value) {
//These are the values I am looking for -> values that are part of the documentEventxx and allowedB.
}
}
}
var result = activityTypes.Select(type => new CategoryViewModel
{
Id = type.Id,//This is where I want to add only items that are in the allowedA array
Text = type.Name,
Types = activities.Where(a => a.ParentId == type.Id).Select(t => new TaxonomyMemberTextItem
{
Id = t.Id, //This is where I want to add only items that are in the allowedB array
Text = t.Name
}).ToList()
}).ToArray();
I have been reading about lambda expressions and foreach loops so please don't just post a random link.
Thanks in advance.
Filter the values before Selecting.
activityTypes.Where(x=>allowedA.Contains(x.Id)).Select(type => new CategoryViewModel
{
Id = type.Id,
Text = type.Name,
Types = activities.Where(a => a.ParentId == type.Id && allowedB.Contains(a.Id)).Select(t => new TaxonomyMemberTextItem
{
Id = t.Id,
Text = t.Name
}).ToList()
})
To filter you use .Where. You .Select to create a list of new types. So in order to filter, then create the lists of objects you want:
var result = activityTypes.Where(type=>isAllowed(type.Id)).Select(type => new CategoryViewModel
{
Id = type.Id,//This is where I want to add only items that are in the allowedA array
Text = type.Name,
Types = activities.Where(a => a.ParentId == type.Id&&isAllowed(a.Id)).Select(t => new TaxonomyMemberTextItem
{
Id = t.Id, //This is where I want to add only items that are in the allowedB array
Text = t.Name
}).ToList()
}).ToArray();