What is the most efficient way to
a) retrieve all children objects from multiple parent types, and
b) know what the parent type is and the exact parent Id for each child?
Currently this is what I'm doing and it's incredibly inefficient, at least the part where I find the specific parent of each child.
public class ChildModel
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ParentType1Model
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ChildModel> Children { get; set; }
}
public class ParentType2Model
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ChildModel> Children { get; set; }
}
//Get all ChildModels from ParentType1
var parentType1Children = db.ParentType1Models
.SelectMany(x => x.Children)
.ToList();
listOfChildModels.AddRange(parentType1Children);
//Get all ChildModels from ParentType2
var parentType2Children = db.ParentType2Models
.SelectMany(x => x.Children)
.ToList();
listOfChildModels.AddRange(parentType2Children);
//Find the parent for each ChildModel
foreach (var child in listOfChildModels)
{
ParentType1Model parentType1ModelCheck = null;
ParentType2Model parentType2ModelCheck = null;
parentType1ModelCheck = await db.ParentType1Models
.Where(p => p.Children
.Any(i => i.Id == child.Id))
.FirstOrDefaultAsync();
//If first check is null, then move to second check
if (taskProjectModelCheck == null)
{
parentType2ModelCheck = await db.ParentType2Models
.Where(p => p.Children
.Any(i => i.Id == child.Id))
.FirstOrDefaultAsync();
}
//Now record the parent type and parent Id in an object containing the original ChildModel and it's parent's info (to be used later for various things)
ChildViewModel childViewModel = new ChildViewModel();
childViewModel.ChildModel = child;
if (parentType1ModelCheck != null)
{
childViewModel.ParentType = "ParentType1";
childViewModel.ParentModelId = parentType1ModelCheck.Id;
}
else if (parentType2ModelCheck != null)
{
childViewModel.ParentType = "ParentType2";
childViewModel.ParentModelId = parentType2ModelCheck.Id;
}
}
How about something like this?
var ids1 = from p in db.ParentType1Models
from c in p.Children
select new
{
parentId = p.Id,
parentName = p.Name,
childName = c.Name,
childId = c.Id,
ParentType = "One"
};
var ids2 = from p in db.ParentType2Models
from c in p.Children
select new
{
parentId = p.Id,
parentName = p.Name,
childName = c.Name,
childId = c.Id,
ParentType = "Two"
};
var results = ids1.Union(ids2).ToList();
I ended up using raw SQL, and it is extremely fast.
By writing a query directly against the database, I was able to go straight to the many to many relationship tables that get created by Entity Framework when I set up the ParentTypeXModels and ChildModels.
result = dbContext.Database.SqlQuery<ANewChildObject>(
"select
ParentModelId = pm.Id,
Id = c.Id,
ParentType = 'ParentType1'
from dbo.ChildModels c
JOIN dbo.ParentType1ModelsChildModels pmT ON c.Id = pmT.ChildModel_Id
JOIN dbo.ParentType1Models pm on pmT.ParentType1Model_Id = pm.Id
UNION ALL
select
ParentModelId = pm.Id,
Id = c.Id,
ParentType = 'ParentType2'
from dbo.ChildModels c
JOIN dbo.ParentType2ModelsChildModels pmT ON c.Id = pmT.ChildModel_Id
JOIN dbo.ParentType2Models pm on pmT.ParentType2Model_Id = pm.Id"
).ToList();
I have a viewmodel
public class RecTotal
{
public string PayType { get; set; }
public decimal TotalPrice { get; set; }
public string Category { get; set; }
}
public class ReconcileViewModel
{
public IEnumerable<RecTotal> RecTotals { get; set; }
public IEnumerable<RecInvoiceLineItem> LineItems { get; set; }
}
How do I create sums of the categories and create a new RecTotal record for each one. Ex:
ReconcileViewModel VM = new ReconcileViewModel();
foreach(POSItemCategory cat in db.POSItemCategories)
{
recLineItems.Where(p => p.Category == cat.ID).Sum(p => p.InvPrice);
}
The end result i'm looking for is something like
VM.RecTotal.Add(Sum(TotalPrice), foreach(Category)
I know I'm close but I just cant quite get it.
I found a way to do this, but it is "Ugly" in my opinion and there has to be a better way to do it....
var test = new List<RecTotal>();
foreach (POSItemCategory cat in db.POSItemCategories)
{
test.Add(new RecTotal
{
NumberOfItems = recLineItems.Where(p => p.Category == cat.ID).Count(),
TotalPrice = recLineItems.Where(p => p.Category == cat.ID).Sum(p => p.InvPrice),
PayType = "All",
Category = cat.Name,
NumberOfInvoices = recLineItems.Where(p => p.Category == cat.ID).Select(p => p.InvID).Distinct().Count()
});
};
VM.RecTotals = test;
Please let me know if there is a better way of doing this.
you can try this
var testdata = new List<RecTotal>();
testdata = recLineItems.Where(x => db.POSItemCategories.Select(a=>a.ID).Contains(x.Category))
.GroupBy(x => x.Category)
.Select(
x =>
new RecTotal()
{
Category = x.Key,
PayType = "All",
TotalPrice = x.Sum(z => z.InvPrice),
NumberOfItems = x.Count(),
NumberOfInvoices = x.Select(p => p.InvID).Distinct().Count()
}).ToList();
I have three models (Applicant, Meeting, City) and I joined three of them. I want to get Count by grouping MeetingId in Applicant model. Here are my models and method I use for populating Dropdownlist in Controller. So, like the "Expired" property in the Controller, how can I obtain the count for the MeetingId by grouping on "TotalMeetingById" property?
Applicant Model:
public class Applicant
{
public int ApplicantID { get; set; }
public DateTime? SubmitDate { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public int MeetingId { get; set; }
}
Meeting Model:
public class Meeting
{
public int MeetingID { get; set; }
public string MeetingName { get; set; }
public DateTime MeetingStartDate { get; set; }
public DateTime? MeetingEndDate { get; set; }
public int? TotalParticipant { get; set; }
public int? MeetingCityId { get; set; }
public int? ParticipantCityAId { get; set; }
public int? ParticipantCityBId { get; set; }
}
City Model:
public class City
{
public int CityID { get; set; }
public string CityName { get; set; }
}
Controller:
private void PopulateDropDownList()
{
var meetingsQuery = repository.Meetings
.GroupJoin(repository.Cities, m => m.MeetingCityId, c => c.CityID, (m, c) => new { m, cA = c.DefaultIfEmpty() })
.SelectMany(z => z.cA.Select(cA => new { m = z.m, cA }))
.GroupJoin(repository.Cities, m => m.m.ParticipantCityAId, c => c.CityID, (m, c) => new { m.m, m.cA, cB = c.DefaultIfEmpty() })
.SelectMany(w => w.cB.Select(cB => new { m = w.m, cA = w.cA, cB }))
.GroupJoin(repository.Cities, m => m.m.ParticipantCityBId, c => c.CityID, (m, c) => new { m.m, m.cA, m.cB, cC = c.DefaultIfEmpty() })
.SelectMany(t => t.cC.Select(cC => new { m = t.m, cA = t.cA, cB = t.cB, cC }))
.Select(
m =>
new
{
CityID = m.cA.CityID,
CityName = m.cA.CityName,
MeetingDate = m.m.MeetingStartDate,
MeetingName = m.m.MeetingName,
NameofMeetingCityIdA = m.cA != null ? m.cA.CityName : null,
NameofMeetingCityIdB = m.cB != null ? m.cB.CityName : null,
NameofMeetingCityIdC = m.cC != null ? m.cC.CityName : null
})
.OrderBy(x => x.CityID)
.AsEnumerable()
.Select(
i => new
{
Value = i.CityID.ToString(),
DisplayValue = string.Format("{0} ({1:dd MMMM yyyy})", i.NameofMeetingCityIdA, i.MeetingDate),
Expired = i.MeetingDate < DateTime.UtcNow,
TotalMeetingById= ??? >>> I cannot get the total count for the related MeetingId at here
}
).ToList();
var selectItems = new List<MyHelpers.MySelectItem>(meetingsQuery.Count);
foreach (var record in meetingsQuery)
{
var item = new MyHelpers.MySelectItem
{
Text = record.DisplayValue,
Value = record.Value
};
if (record.Expired)
{
item.Class = "disabled";
item.Disabled = "disabled";
}
selectItems.Add(item);
}
ViewBag.MeetingData = selectItems;
}
Here are sample data for models:
Applicant:
ApplicantID : 100
SubmitDate : 01/11/2013
Name : Christof
Surname : Jahnsen
MeetingId : 1
Meeting:
MeetingID : 1
MeetingName : City Information Days
MeetingStartDate : 01/01/2014
MeetingEndDate : 02/01/2014
TotalParticipant : 2 (for example)
MeetingCityId : 500
ParticipantCityAId : 501
ParticipantCityBId : 502
City:
CityID : 500 / 501 / 502
CityName : London / Paris / NY
Update -----------------------------------------------------------------------
Razor:
#Html.LabelFor(m => m.Applicant.MeetingId)
#Html.MyDropdownListFor(m => m.Applicant.MeetingId, ViewBag.MeetingData as List<MyHelpers.MySelectItem>, "---- Select ----",
new { name = "meetingId", id = "meetingId" })
#Html.ValidationMessageFor(m => m.Applicant.MeetingId, null, new { #class = "ValidationErrors" })
Controller:
public ViewResult Add()
{
PopulateDropDownList();
ApplicantViewModel model = new ApplicantViewModel
{
Applicant = new Applicant(),
Applicants = repository.Applicants,
Lookups = repository.Lookups,
Cities = repository.Cities
.ToList()
};
return View(model);
}
[HttpPost]
public ActionResult Add(ApplicantViewModel model)
{
ApplicantViewModel viewModel;
if (ModelState.IsValid)
{
model.Applicant.SubmitDate = DateTime.Now;
repository.SaveApplicant(model.Applicant);
PopulateDropDownList(model.Applicant);
return View("Completed", ViewBag.ApplicantId = model.Applicant.ApplicantID);
}
else
{
// there is something wrong with the data values
PopulateDropDownList();
TempData["message"] = "Please try again.";
viewModel = new ApplicantViewModel
{
Applicant = new Applicant(),
Applicants = repository.Applicants,
Lookups = repository.Lookups,
Cities = repository.Cities
.ToList()
};
return View(viewModel);
}
}
You need grouping, so use something like this
var meetingsQuery = from meeting in repository.Meetings
join cityA in repository.Cities on meeting.MeetingCityId equals cityA.CityID into CitiesA
join cityB in repository.Cities on meeting.ParticipantCityAId equals cityB.CityID into CitiesB
join cityC in repository.Cities on meeting.ParticipantCityBId equals cityC.CityID into citiesC
from cityA in citiesA.DefaultIfEmpty()
from cityB in citiesB.DefaultIfEmpty()
from cityC in citiesC.DefaultIfEmpty()
orderby cityA.CityID
select new
{
CityID = cityA.CityID,
CityName = cityA.CityName,
MeetingDate = meeting.MeetingStartDate,
MeetingName = meeting.MeetingName,
NameofMeetingCityIdA = cityA != null ? cityA.CityName : null,
NameofMeetingCityIdB = cityB != null ? cityB.CityName : null,
NameofMeetingCityIdC = cityC != null ? cityC.CityName : null
}
var meetings = from meeting in meetingsQuery.AsEnumerable()
group meeting by new {
meeting.CityID,
meeting.MeetingDate,
meeting.NameofMeetingCityIdA
} into grouppedMeeting
select new {
Value = grouppedMeeting.Key.CityID.ToString(),
DisplayValue = string.Format("{0} ({1:dd MMMM yyyy})", grouppedMeeting.Key.NameofMeetingCityIdA, grouppedMeeting.Key.MeetingDate),
Expired = grouppedMeeting.Key.MeetingDate < DateTime.UtcNow,
TotalMeetingById= grouppedMeeting.Count()
}
UPDATE
in this code
// there is something wrong with the data values
PopulateDropDownList();
TempData["message"] = "Please try again.";
viewModel = new ApplicantViewModel
{
Applicant = new Applicant(),
Applicants = repository.Applicants,
Lookups = repository.Lookups,
Cities = repository.Cities
.ToList()
};
return View(viewModel);
you don't mark any item as selected, you only add items to viewbag
Finally I solved the problem with the help of using an external method out of Lambda expression.
private void PopulateMeetingsDropDownList(object selectedMeetings = null)
{
var meetingsQuery = repository.Meetings
.GroupJoin(repository.Cities, m => m.MeetingCityId, c => c.CityID, (m, c) => new { m, cA = c.DefaultIfEmpty() })
.SelectMany(z => z.cA.Select(cA => new { m = z.m, cA }))
.GroupJoin(repository.Cities, m => m.m.ParticipantCityAId, c => c.CityID, (m, c) => new { m.m, m.cA, cB = c.DefaultIfEmpty() })
.SelectMany(w => w.cB.Select(cB => new { m = w.m, cA = w.cA, cB }))
.GroupJoin(repository.Cities, m => m.m.ParticipantCityBId, c => c.CityID, (m, c) => new { m.m, m.cA, m.cB, cC = c.DefaultIfEmpty() })
.SelectMany(t => t.cC.Select(cC => new { m = t.m, cA = t.cA, cB = t.cB, cC }))
.Select(
m =>
new
{
TotalParticipant = m.m.TotalParticipant,
MeetingID = m.m.MeetingID,
CityID = m.cA.CityID,
CityName = m.cA.CityName,
MeetingDate = m.m.MeetingStartDate,
MeetingName = m.m.MeetingName,
NameofMeetingCityIdA = m.cA != null ? m.cA.CityName : null,
NameofMeetingCityIdB = m.cB != null ? m.cB.CityName : null,
NameofMeetingCityIdC = m.cC != null ? m.cC.CityName : null
})
.OrderBy(x => x.CityName)
.AsEnumerable()
.Select(
i => new
{
Value = i.MeetingID.ToString(),
DisplayValue = string.Format("{0} ({1:dd MMMM yyyy})", i.NameofMeetingCityIdA, i.MeetingDate)),
Expired = i.MeetingDate < DateTime.UtcNow,
MaksimumCount = i.TotalParticipant,
CurrentCount = GetMeetingCount(i.MeetingID)
}
).ToList();
var selectItems = new List<MyHelpers.MySelectItem>(meetingsQuery.Count);
foreach (var record in meetingsQuery)
{
var item = new MyHelpers.MySelectItem
{
Text = record.DisplayValue,
Value = record.Value
};
//If Meeting Date is expired or Count for the current record >= Total Participant
if (record.Expired || record.CurrentCount >= record.MaksimumCount)
{
item.Class = "disabled";
item.Disabled = "disabled";
}
selectItems.Add(item);
}
ViewBag.MeetingData = selectItems;
}
public int GetMeetingCount(int meetingId)
{
return repository.Applicants.Count(x => x.MeetingId == meetingId);
}
The first running of the code I encountered "There is already an open DataReader associated with this Command which must be closed first." error. But adding "MultipleActiveResultSets=True;" parameter to teh ConnectionString solved this problem and now it works properly.
i am creating one Kendo treeview as written below
#(Html.Kendo().TreeView()
.Name("treeview")
.Template("<a class='edit-link' onclick=javascript:EditNode(#= item.id #) href='\\#'>#= item.text #</a> <a class='add-link' onclick=javascript:AddNode(#= item.id #) href='\\#'>Add</a>")
.HtmlAttributes(new { #class = "demo-section" })
.DataSource(source =>
{
source.Read(read => read.Action("Read_TemplateData", "Role"));
})
)
and in the controller action i am returning like
public ActionResult Read_TemplateData(string id)
{
IEnumerable<KendoTreeviewModel> result;
var AllPrivileges = ContextService.GetAllPrivilege(Evry.Ecompanion.Web.Common.SessionManager.AuthorizedInfo.UserId);
if (string.IsNullOrEmpty(id))
{
result = AllPrivileges.Where(p => p.Id == p.ParentPrivilegeId).Select(p => new KendoTreeviewModel { text = p.Name, id = p.Id,expanded=false, items = GetChilderns(p.Id) }).ToList();
}
else
{
result = AllPrivileges.Where(p => p.ParentPrivilegeId == Convert.ToInt32(id, CultureInfo.InvariantCulture) && p.Id != Convert.ToInt32(id, CultureInfo.InvariantCulture)).Select(p => new KendoTreeviewModel { text = p.Name, id = p.Id}).ToList();
}
return Json(result, JsonRequestBehavior.AllowGet);
}
public List<KendoTreeviewModel> GetChilderns(int id)
{
var AllPrivileges = ContextService.GetAllPrivilege(Evry.Ecompanion.Web.Common.SessionManager.AuthorizedInfo.UserId);
return AllPrivileges.Where(p => p.ParentPrivilegeId == Convert.ToInt32(id, CultureInfo.InvariantCulture) && p.Id != Convert.ToInt32(id, CultureInfo.InvariantCulture)).Select(p => new KendoTreeviewModel { text = p.Name, id = p.Id }).ToList();
}
and the viewmodel is like
public class KendoTreeviewModel
{
[DataMember]
public int id { get; set; }
[DataMember]
public string text { get; set; }
[DataMember]
public bool expanded { get; set; }
[DataMember]
public List<KendoTreeviewModel> items { get; set; }
}
in the result the Parent and child lists are coming, but the expander in the treeview is not coming
the output is coming without treeview expander, only parent nodes are displaying.
please anybody help me in resolving the issue.
Thanks in advance,
Rudresh
you are not passing Id to your controller
source.Read(read => read.Action("Read_TemplateData", "Role", new{id=#= item.id #}));
You need hasChildren property in order to get the child records
in KendoTreeviewModel class add this property hasChildren then
change
result = AllPrivileges.Where(p => p.Id == p.ParentPrivilegeId).Select(p => new KendoTreeviewModel { text = p.Name, id = p.Id,expanded=false, items = GetChilderns(p.Id) }).ToList();
to
result = AllPrivileges.Where(p => p.Id == p.ParentPrivilegeId).Select(p => new KendoTreeviewModel { text = p.Name, id = p.Id,expanded=false, items = GetChilderns(p.Id),
hasChildren = GetChilderns(p.Id).count() > 0}).ToList();
There are several same questions that have same problem. But I cant find solution for me.
LinQ
var result = (from a in entity.TblAnalizorReadings
group a by new { date = new DateTime(((DateTime)a.okuma_tarihi).Year, ((DateTime)a.okuma_tarihi).Month, ((DateTime)a.okuma_tarihi).Day, ((DateTime)a.okuma_tarihi).Hour, 0, 0) } into g
select new AnalizorPivotChartModel
{
okuma_tarihi = g.Key.date,
Gerilim_Faz1 = g.Max(x => x.Gerilim_Faz1),
Gerilim_Faz2 = g.Max(x => x.Gerilim_Faz2),
Gerilim_Faz3 = g.Max(x => x.Gerilim_Faz3)
}).ToList();
Model
public class AnalizorPivotChartModel
{
public Nullable<System.DateTime> okuma_tarihi { get; set; }
public Nullable<decimal> Gerilim_Faz1 { get; set; }
public Nullable<decimal> Gerilim_Faz2 { get; set; }
public Nullable<decimal> Gerilim_Faz3 { get; set; }
}
I get error message as this question title. I can write more code if its neccesary.
Thanks.
var result = entity.TblAnalizorReadings
.GroupBy(a =>
new {
((DateTime)a.okuma_tarihi).Year,
((DateTime)a.okuma_tarihi).Month,
((DateTime)a.okuma_tarihi).Day,
((DateTime)a.okuma_tarihi).Hour
},
(k, g) => new {
okuma_tarihi = k,
Gerilim_Faz1 = g.Max(x => x.Gerilim_Faz1),
Gerilim_Faz2 = g.Max(x => x.Gerilim_Faz2),
Gerilim_Faz3 = g.Max(x => x.Gerilim_Faz3)
})
.AsEnumerable()
.Select(g => new AnalizorPivotChartModel
{
okuma_tarihi = new DateTime(okuma_tarihi.Year, okuma_tarihi.Month, okuma_tarihi.Day, okuma_tarihi.Hour, 0, 0),
Gerilim_Faz1 = g.Gerilim_Faz1,
Gerilim_Faz2 = g.Gerilim_Faz2,
Gerilim_Faz3 = g.Gerilim_Faz3
})
.ToList();