Linq SelectMany With Null Child - c#

MenuSetup and AccessRules have a one to many relation as described below.
public class MenuSetup
{
public virtual int MenuId { get; set; }
public virtual string DisplayText { get; set; }
public virtual int MenuOrder { get; set; }
public virtual bool MenuStatus { get; set; }
public virtual bool HasKids { get; set; }
public virtual IList<MenuAccessRules> AccessRules { get; set; }
}
public class MenuAccessRules
{
public virtual int Id { get; set; }
public virtual Boolean CanCreate { get; set; }
public virtual Boolean CanUpdate { get; set; }
public virtual Boolean CanDelete { get; set; }
public virtual FamsRoles Roles { get; set; }
public virtual MenuSetup Menu { get; set; }
}
I want to project the result of the query below in a view model
var result = session.QueryOver<MenuSetup>()
.Where(p => p.MenuId == id)
.List();
var vs = result.SelectMany(x => x.AccessRules, (a, b) => new MenuDetailsViewModel
{
MenuId = a.MenuId,
DisplayText = a.DisplayText,
MenuOrder = a.MenuOrder,
HasKids = a.HasKids,
MenuStatus = a.MenuStatus,
AccessRuleLists = a.AccessRules.
Select(c => new AccessRulesList {
Id = b.Id,
MenuId = b.Menu.MenuId,
RoleId = b.Roles.RoleId,
CanCreate = b.CanCreate,
CanUpdate = b.CanUpdate,
CanDelete = b.CanDelete }).ToList()
}).SingleOrDefault();
When AccessRules has data, vs returns MenuDetailsViewModel, but when AccessRules is Empty vs returns null.
Please how do i craft my selectMany to return MenuDetailsViewModel irrespective of AccessRules data.
Thanks in advance for your help

Would something like this:
var vs = result.Select(x => new MenuDetailsViewModel
{
MenuId = x.MenuId,
DisplayText = x.DisplayText,
MenuOrder = x.MenuOrder,
HasKids = x.HasKids,
MenuStatus = x.MenuStatus,
AccessRuleLists = x.AccessRules == null ? null : x.AccessRules.
Select(c => new AccessRulesList
{
Id = c.Id,
MenuId = c.Menu.MenuId,
RoleId = c.Roles.RoleId,
CanCreate = c.CanCreate,
CanUpdate = c.CanUpdate,
CanDelete = c.CanDelete
}).ToList()
}).SingleOrDefault();

Check below code it may help
var vs = result.SkipWhile(a=> a.AccessRules==null).SelectMany(x => x.AccessRules, (a, b) => new MenuDetailsViewModel
{
MenuId = a.MenuId,
DisplayText = a.DisplayText,
MenuOrder = a.MenuOrder,
HasKids = a.HasKids,
MenuStatus = a.MenuStatus,
AccessRuleLists = a.AccessRules.
Select(c => new AccessRulesList {
Id = b.Id,
MenuId = b.Menu.MenuId,
RoleId = b.Roles.RoleId,
CanCreate = b.CanCreate,
CanUpdate = b.CanUpdate,
CanDelete = b.CanDelete }).ToList()
}).SingleOrDefault();

Related

at least one object must implement icomparable. orderby descending C#

I'm trying to order the list of Custom object by its nested object property updatedDate but it throws error. I want to order the Store list based on nested property field PartsInformation.updatedDate then by PartsDetail.updatedDate. If you need more details, let me know and I will try to update it. I tried with Icomparable but I'm new to that so I didn't proceed further.
Class Structure:
public class StoreHomeInfo
{
public string StoreID { get; set; }
public string StoreName { get; set; }
public List<OperationalUnit> OperationalUnitData { get; set; }
}
public class OperationalUnit
{
public string OunitID { get; set; }
public string OunitName { get; set; }
public List<PartsInformation> PartData { get; set; }
public List<PartsDetail> PartCost { get; set; }
}
public class PartsInformation
{
public string PartID { get; set; }
public string Partname { get; set; }
public string Summary { get; set; }
public string StoreID { get; set; }
public string OunitID { get; set; }
public DateTime? updatedDate { get; set; }
}
public class PartsDetail
{
public string PartsDetailID { get; set; }
public string PartDetailName { get; set; }
public string Summary { get; set; }
public string OunitID { get; set; }
public string StoreID { get; set; }
public DateTime? updatedDate { get; set; }
}
Sample Query :
var result = (from st in lstobjStoreDetails
group st by new { st.ID, st.Storename } into grouped
select new StoreHomeInfo()
{
StorID = grouped.Key.ID,
StoreName = grouped.Key.Storename,
OperationalUnitData = (from ser in lstobjOpUnitDetails
where ser.StorID.Equals(grouped.Key.ID)
group ser by new { ser.ID, ser.Ounitname } into
grouped1
select new OperationalUnit()
{
OunitID = grouped1.Key.ID,
OunitName = grouped1.Key.Ounitname,
PartsInformation = (from projes in lstobjpartDetails
where projes.OunitID.Equals(grouped1.Key.ID)
group serviceBS by new { projes.PartID, projes.Partname, projes.StorID, projes.OunitID,projes.updatedDate } into groupedparts
select new PartsInformation()
{
PartID = lstobjpartDetails.Where(q => q.StorID == grouped.Key.ID && q.OunitID == grouped1.Key.ID && q.PartID == groupedparts.Key.PartID).FirstOrDefault() != null ? lstobjpartDetails.Where(q => q.StorID == grouped.Key.ID && q.OunitID == grouped1.Key._ID && q.PartID == groupedparts.Key.PartID).FirstOrDefault().PartID : null,
Partname = groupedparts.Key.Partname,
Summary = groupedparts.Key.Summary,
OunitID = grouped1.Key.ID,
StorID = grouped.Key.ID,
updatedDate = Convert.ToDateTime(groupedparts.Key.updatedDate)
}).ToList(),
PartCost = (from pes in lstobjpartCostDetails
where pes.OunitID.Equals(grouped1.Key._ID)
group serviceBS by new { pes.PartsDetailID, pes.PartDetailName, pes.OunitID, pes.Summary pes.updatedDate, pes.StorID} into grouped2
select new PartsDetail()
{
PartsDetailID = lstobjpartCostDetails.Where(q => q.StorID == grouped.Key._ID && q.OunitID == grouped1.Key._ID && q.PartsDetailID == grouped2.Key.PartsDetailID).FirstOrDefault() != null ? lstobjpartCostDetails.Where(q => q.StorID == grouped.Key._ID && q.OunitID == grouped1.Key._ID && q.PartsDetailID == grouped2.Key.PartsDetailID).FirstOrDefault().PartsDetailID : null,
PartDetailName = grouped2.Key.PartDetailName,
Summary = grouped2.Key.Summary,
StorID = grouped.Key.ID,
OunitID = grouped1.Key.ID,
updatedDate = Convert.ToDateTime(grouped2.Key.updatedDate)
}).ToList()
}).ToList()
}).OrderByDescending(n => n.OperationalUnitData.OrderByDescending(p => p.PartCost != null && p.PartCost.Any() ? p.PartCost.OrderByDescending(q => q.updatedDate) : null)
.ThenBy(x => x.PartsInformation != null && x.PartsInformation.Any() ? x.PartsInformation.OrderByDescending(y => y.updatedDate) : null)).ToList();
This part of the code:
.OrderByDescending(p => p.PartCost != null && p.PartCost.Any() ? p.PartCost.OrderByDescending(q => q.updatedDate) : null)
is trying to order a list of OperationalUnits, but the key on which you're ordering by is a List<PartCost>. I suspect you want a member of that list to order by.
As an aside, you're trying to do a lot of work in one line and your code would be far clearer if you separated out methods to go into the OrderByDescending calls.

How select hierarchy from child to parent using linq for entities or EF Core 2?

There is a hierarchy of four entities (models). All entities have relationships one to many. It's looks following:
public class Region
{
public Guid Id { get; set; }
public int RegionId { get; set; }
public virtual ICollection<District> Districts { get; set; }
}
public class District
{
public Guid Id { get; set; }
public int DistrictId { get; set; }
public virtual ICollection<Building> Buildings { get; set; }
public int RegionId { get; set; }
public Region Region { get; set; }
}
public class Building
{
public Guid Id { get; set; }
public int BuildingId { get; set; }
public int DistrictId { get; set; }
public virtual ICollection<Flat> Flats { get; set; }
public District District { get; set; }
}
public class Flat
{
public Guid Id { get; set; }
public int FlatId { get; set; }
public int BuildingId { get; set; }
public Building Building { get; set; }
}
It is hierarchy like: Region->District->Building->Flat.
I want return collection of Flat thats include all related entities from top.
I do it folowing:
var flat = _context.Flats
.Include(t => t.Building)
.Include(b=>b.Building.District)
.Include(b => b.Building.District.Region).GetPaged(PageNumber, 20);
But for some reason is return breaking result....
[{"id":"6cbb1431-36d4-490c-a047-c211e4db3bdd","flatId":29570,"roomsCount":1,"totalArea":41.95,"kitchenArea":11.85,"floor":21,"buildingId":130,"price":5725650.00,"building":{"id":"03baca1e-02e9-4ee0-ae47-920e3eb0d5bb","buildingId":130,"name":"NNN","queue":1,"housing":"1","districtId":13003,"flats":[
It breaks for some reason on public virtual ICollection<Flat> Flats { get; set; }. I can't remove it becasue it is needed for FK.
The following query works:
_context.Flat
.Join(
_context.Building,
f => f.BuildingId,
b => b.BuildingId,
(f, b) =>
new
{
f = f,
b = b
}
)
.Join(
_context.District,
temp0 => temp0.b.DistrictId,
d => d.DistrictId,
(temp0, d) =>
new
{
temp0 = temp0,
d = d
}
)
.Join(
_context.Region,
temp1 => temp1.d.RegionId,
r => r.RegionId,
(temp1, r) =>
new
{
Id = temp1.temp0.f.Id,
FlatId = temp1.temp0.f.FlatId,
Floor = temp1.temp0.f.Floor,
RoomsCount = temp1.temp0.f.RoomsCount,
TotalArea = temp1.temp0.f.TotalArea,
KitchenArea = temp1.temp0.f.KitchenArea,
Price = temp1.temp0.f.Price,
Building = new
{
Id = temp1.temp0.b.Id,
BuildingId = temp1.temp0.b.Id,
Name = temp1.temp0.b.Name,
Queue = temp1.temp0.b.Queue,
Housing = temp1.temp0.b.Housing,
District = new
{
Id = temp1.d.Id,
DistrictId = temp1.d.DistrictId,
Name = temp1.d.Name,
Regions = new
{
Id = r.Id,
RegionId = r.Id,
Name = r.Name
}
}
}
}
).GetPaged(PageNumber, PageSize)
And it is return what i whant:
{
"id": "a49a0a48-370b-46da-b6da-ea4040cc1431",
"flatId": 84095,
"roomsCount": 3,
"totalArea": 76.5,
"kitchenArea": 11.07,
"floor": 18,
"buildingId": 0,
"price": 5567500,
"building": {
"id": "037c4074-3ff5-4fbd-92ea-88c8f746b883",
"buildingId": 200,
"name": "NNNN",
"queue": 3,
"housing": "4",
"districtId": 0,
"flats": null,
"district": {
"id": "db031e09-1d6c-41f4-9e45-ec6170e3df8b",
"districtId": 5005,
"name": "Distr",
"buildings": null,
"regionId": 0,
"region": {
"id": "5ac5766f-e62e-4da9-86cf-e4a85423503a",
"regionId": 5001,
"name": "Region",
"districts": null
}
}
}
}
But it is looks like cumbersome.
How can I do it using EF features? Or maybe somehow to reduce linq? And why include() return breaking result?
P.S. .GetPaged(PageNumber, 20); is extension method for pagination and he is working fine.
My suggesstion is below
var flag = (from f in _context.Flags
join b in _context.Buildings
on b.BuildingId equals f.BuildingId
join d in _context.Districts
on d.DistrictId equals b.DistrictId
join r in _context.Regions
on r.RegionId equals d.RegionId
select new
{ ...
}).GetPaged(PageNumber, 20);
You can get any property from Building, District and Region to populate to your result object.

Get 1 record from 2 tables ASP.NET

I am still an ASP.NET amateur and I've been working on an application that needs to calculate the hours an employee has worked if no special events have come up e.g the employee has been sick, I have 2 tables in my database, 1 with the employees. and a second table which holds the events. the events table is filled through a calendar and holds info like dates and who made the event.
My situation:
When the user clicks on an employee's detail page. I want the corresponding record of the employee, and the events he made. So I am assuming that I am looking for a join with linq.
An employee can make more than 1 event, let's say an employee needs to work overtime 3 days this month. then on the detail page, it should select the employee from the employee table and the 3 events from the events table.
Update
Thanks to Vladimir's help, a whole lot of errors are gone and the query works. Though it does not completely work as expected yet. it currently returns 1 employee and 1 event. While the employee that I am testing with, should have 4 events returned.
This is my Context
namespace hrmTool.Models
{
public class MedewerkerMeldingContext : DbContext
{
public MedewerkerMeldingContext() : base("name=temphrmEntities") { }
public DbSet<medewerker> medewerker { get; set; }
public DbSet<medewerker_melding> medewerker_melding { get; set; }
}
}
My current viewModel
namespace hrmTool.Models
{
public class MedewerkerMeldingViewModel
{
//Medewerker tabel
public int ID { get; set; }
public string roepnaam { get; set; }
public string voorvoegsel { get; set; }
public string achternaam { get; set; }
public string tussenvoegsel { get; set; }
public string meisjesnaam { get; set; }
public Nullable<System.DateTime> datum_in_dienst { get; set; }
public Nullable<System.DateTime> datum_uit_dienst { get; set; }
public int aantal_km_woon_werk { get; set; }
public bool maandag { get; set; }
public Nullable<System.TimeSpan> ma_van { get; set; }
public Nullable<System.TimeSpan> ma_tot { get; set; }
public bool dinsdag { get; set; }
public Nullable<System.TimeSpan> di_van { get; set; }
public Nullable<System.TimeSpan> di_tot { get; set; }
public bool woensdag { get; set; }
public Nullable<System.TimeSpan> wo_van { get; set; }
public Nullable<System.TimeSpan> wo_tot { get; set; }
public bool donderdag { get; set; }
public Nullable<System.TimeSpan> do_van { get; set; }
public Nullable<System.TimeSpan> do_tot { get; set; }
public bool vrijdag { get; set; }
public Nullable<System.TimeSpan> vr_van { get; set; }
public Nullable<System.TimeSpan> vr_tot { get; set; }
public bool zaterdag { get; set; }
public Nullable<System.TimeSpan> za_van { get; set; }
public Nullable<System.TimeSpan> za_tot { get; set; }
public bool zondag { get; set; }
public Nullable<System.TimeSpan> zo_van { get; set; }
public Nullable<System.TimeSpan> zo_tot { get; set; }
//Medewerker_Melding combi tabel
public int medewerkerID { get; set; }
public int meldingID { get; set; }
public System.DateTime datum_van { get; set; }
public Nullable<System.DateTime> datum_tot { get; set; }
public int MM_ID { get; set; }
public virtual ICollection<medewerker_melding> medewerker_melding { get; set; }
public virtual medewerker medewerker { get; set; }
}
}
My current query
using (var context = new MedewerkerMeldingContext())
{
var medewerkers = context.medewerker;
var medewerker_meldings = context.medewerker_melding;
var testQuery = from m in medewerkers
join mm in medewerker_meldings on m.ID equals mm.medewerkerID
where m.ID == id
select new MedewerkerMeldingViewModel
{
ID = m.ID,
roepnaam = m.roepnaam,
voorvoegsel = m.voorvoegsel,
achternaam = m.achternaam,
tussenvoegsel = m.tussenvoegsel,
meisjesnaam = m.meisjesnaam,
datum_in_dienst = m.datum_in_dienst,
datum_uit_dienst = m.datum_uit_dienst,
aantal_km_woon_werk = m.aantal_km_woon_werk,
maandag = m.maandag,
ma_van = m.ma_van,
ma_tot = m.ma_tot,
dinsdag = m.dinsdag,
di_van = m.di_van,
di_tot = m.di_tot,
woensdag = m.woensdag,
wo_van = m.wo_van,
wo_tot = m.wo_tot,
donderdag = m.donderdag,
do_van = m.do_van,
do_tot = m.do_tot,
vrijdag = m.vrijdag,
vr_van = m.vr_van,
vr_tot = m.vr_tot,
zaterdag = m.zaterdag,
za_van = m.za_van,
za_tot = m.za_tot,
zondag = m.zondag,
zo_van = m.zo_van,
zo_tot = m.zo_tot,
medewerkerID = mm.medewerkerID,
meldingID = mm.meldingID,
datum_van = mm.datum_van,
datum_tot = mm.datum_tot,
MM_ID = mm.ID
};
var getQueryResult = testQuery.FirstOrDefault();
Debug.WriteLine("Debug testQuery" + testQuery);
Debug.WriteLine("Debug getQueryResult: "+ getQueryResult);
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
if (testQuery == null)
{
return HttpNotFound();
}
return View(getQueryResult);
}
Returns: 1 instance of employee and only 1 event
Expected return: 1 instance of employee, 4 events
In your context DbContext is missing - so Linq to Entity can not find corresponding implementation of the query. And also DbContext operates with the
DbSets - so try:
public class MedewerkerMeldingContext : DbContext
{
public MedewerkerMeldingContext () : base(ConnectionStringKey)
{
};
public DbSet<medewerker> medewerker { get; set; }
public DbSet<medewerker_melding> medewerker_melding { get; set; }
}
then
using (var context = new MedewerkerMeldingContext())
{
var medewerkers = context.medewerker;
var medewerker_meldings = context.medewerker_melding;
var testQuery = from m in medewerkers
join mm in medewerker_meldings on m.ID equals mm.medewerkerID
where m.ID == id
select new MedewerkerMeldingViewModel
{
ID = m.ID,
roepnaam = m.roepnaam,
voorvoegsel = m.voorvoegsel,
achternaam = m.achternaam,
tussenvoegsel = m.tussenvoegsel,
meisjesnaam = m.meisjesnaam,
datum_in_dienst = m.datum_in_dienst,
datum_uit_dienst = m.datum_uit_dienst,
aantal_km_woon_werk = m.aantal_km_woon_werk,
maandag = m.maandag,
ma_van = m.ma_van,
ma_tot = m.ma_tot,
dinsdag = m.dinsdag,
di_van = m.di_van,
di_tot = m.di_tot,
woensdag = m.woensdag,
wo_van = m.wo_van,
wo_tot = m.wo_tot,
donderdag = m.donderdag,
do_van = m.do_van,
do_tot = m.do_tot,
vrijdag = m.vrijdag,
vr_van = m.vr_van,
vr_tot = m.vr_tot,
zaterdag = m.zaterdag,
za_van = m.za_van,
za_tot = m.za_tot,
zondag = m.zondag,
zo_van = m.zo_van,
zo_tot = m.zo_tot,
medewerkerID = mm.medewerkerID,
meldingID = mm.meldingID,
datum_van = mm.datum_van,
datum_tot = mm.datum_tot,
MM_ID = mm.ID
};
Debug.WriteLine("Debug testQuery" + testQuery);
var getQueryResult = testQuery.ToList();
Debug.WriteLine("Debug getQueryResult: " + getQueryResult);
var resultDictionary = getQueryResult.GroupBy(x => x.ID).ToDictionary(y => y.Key, z => z.ToList());
Debug.WriteLine("resultDictionary: " + resultDictionary);
var firstItem = resultDictionary.Values.First();
Debug.WriteLine("FirstItem: " + firstItem);
var Entity = new newEntity
{
//ID = firstItem.ID,
ID = firstItem.Select(x => x.ID).First(),
roepnaam = firstItem.Select(x => x.roepnaam).First(),
voorvoegsel = firstItem.Select(x => x.voorvoegsel).First(),
achternaam = firstItem.Select(x => x.achternaam).First(),
tussenvoegsel = firstItem.Select(x => x.tussenvoegsel).First(),
meisjesnaam = firstItem.Select(x => x.meisjesnaam).First(),
datum_in_dienst = firstItem.Select(x => x.datum_in_dienst).First(),
datum_uit_dienst = firstItem.Select(x => x.datum_uit_dienst).First(),
aantal_km_woon_werk = firstItem.Select(x => x.aantal_km_woon_werk).First(),
maandag = firstItem.Select(x => x.maandag).First(),
ma_van = firstItem.Select(x => x.ma_van).First(),
ma_tot = firstItem.Select(x => x.ma_tot).First(),
dinsdag = firstItem.Select(x => x.dinsdag).First(),
di_van = firstItem.Select(x => x.di_van).First(),
di_tot = firstItem.Select(x => x.di_tot).First(),
woensdag = firstItem.Select(x => x.woensdag).First(),
wo_van = firstItem.Select(x => x.wo_van).First(),
wo_tot = firstItem.Select(x => x.wo_tot).First(),
donderdag = firstItem.Select(x => x.donderdag).First(),
do_van = firstItem.Select(x => x.do_van).First(),
do_tot = firstItem.Select(x => x.do_tot).First(),
vrijdag = firstItem.Select(x => x.vrijdag).First(),
vr_van = firstItem.Select(x => x.vr_van).First(),
vr_tot = firstItem.Select(x => x.vr_tot).First(),
zaterdag = firstItem.Select(x => x.zaterdag).First(),
za_van = firstItem.Select(x => x.za_van).First(),
za_tot = firstItem.Select(x => x.za_tot).First(),
zondag = firstItem.Select(x => x.zondag).First(),
zo_van = firstItem.Select(x => x.zo_van).First(),
zo_tot = firstItem.Select(x => x.zo_tot).First()
};
Debug.WriteLine("Entity: " + Entity);
var plainValues = resultDictionary.Values.SelectMany(x => x).ToList();
var resultSchedule = plainValues.Select(x => new medewerker_melding
{
medewerkerID = x.medewerkerID,
meldingID = x.meldingID,
datum_van = x.datum_van,
datum_tot = x.datum_tot,
ID = x.MM_ID
}).ToList();
Entity.medewerker_melding = resultSchedule;
}
You need to check whether MedewerkerMeldingContext dbC = new MedewerkerMeldingContext(); is implementing IEnumerable<T> else, you will not be able to preform the desired action on the table.
This kind of error (Could not find an implementation of the query
pattern) usually occurs when:
You are missing LINQ namespace usage (using System.Linq)
Typeyou are querying does not implement IEnumerable<T>
What i'd recommend, first check the namespace.
Second check for the IEnumerable<T> implementation.
Your query is good enough, you take the context and perform the linq, no issue here. It is 90% that you forgot the namespace since context is already implementing the IEnumerable<T> interface.

Entity Framework: Not being able to remove child data

Error is throwing when control iterate in foreach loop.
foreach (var existingAddress in existingCustomer.Addresses.Where(a => a.AddressID == 5).ToList())
{
foreach (var CustContacts in existingAddress.Contacts.Where(a => a.ContactID == 5))
{
CurrentContacts = CustContacts;
existingAddress.Contacts.Remove(CurrentContacts);
//CurrentAddress.Contacts.ToList().ForEach(r => db.Contacts.Remove(CurrentContacts));
}
CurrentAddress = existingAddress;
existingCustomer.Addresses.Remove(CurrentAddress);
//existingCustomer.Addresses.ToList().ForEach(r => db.Addresses.Remove(CurrentAddress));
}
When this line existingAddress.Contacts.Remove(CurrentContacts); executes, then error message is
Collection was modified; enumeration operation may not execute.
If I execute this line CurrentAddress.Contacts.ToList().ForEach(r => db.Contacts.Remove(CurrentContacts)); instead of this line existingAddress.Contacts.Remove(CurrentContacts); then error message i am getting
Additional information: Object reference not set to an instance of an object.
I am new in EF so I am not being able to figure out how to remove data from child table.
My entity relationship is Customer > Address > Contacts
A customer may have multiple address and each address may have multiple contact details.
My full code as follows which I used to update parent customer object and trying to remove specific data from address and contact child table and also insert two new data in child table.
private void button3_Click(object sender, EventArgs e)
{
Addresses CurrentAddress = null;
Contacts CurrentContacts = null;
using (var db = new TestDBContext())
{
var existingCustomer = db.Customer
.Include(a => a.Addresses.Select(x => x.Contacts))
.FirstOrDefault(p => p.CustomerID == 5);
existingCustomer.FirstName = "Test Customer122";
// selecting address
foreach (var existingAddress in existingCustomer.Addresses.Where(a => a.AddressID == 5).ToList())
{
foreach (var CustContacts in existingAddress.Contacts.Where(a => a.ContactID == 5))
{
CurrentContacts = CustContacts;
existingAddress.Contacts.Remove(CurrentContacts);
//CurrentAddress.Contacts.ToList().ForEach(r => db.Contacts.Remove(CurrentContacts));
}
CurrentAddress = existingAddress;
existingCustomer.Addresses.Remove(CurrentAddress);
//existingCustomer.Addresses.ToList().ForEach(r => db.Addresses.Remove(CurrentAddress));
}
Addresses oAdrModel = new Addresses();
oAdrModel.Address1 = "test add2";
oAdrModel.Address2 = "test add2";
oAdrModel.SerialNo = 3;
oAdrModel.IsDefault = true;
oAdrModel.CustomerID = existingCustomer.CustomerID;
db.Addresses.Add(oAdrModel);
Contacts ContactModel = new Contacts();
ContactModel.Phone = "1111111-33";
ContactModel.Fax = "1-1111111";
ContactModel.SerialNo = 4;
ContactModel.IsDefault = true;
ContactModel.AddressID = CurrentAddress.AddressID;
db.Contacts.Add(ContactModel);
db.SaveChanges();
}
}
Entity related classes
public class CustomerBase
{
public int CustomerID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[NotMapped]
public string Address1 { get; set; }
[NotMapped]
public string Address2 { get; set; }
[NotMapped]
public string Phone { get; set; }
[NotMapped]
public string Fax { get; set; }
}
public class Customer : CustomerBase
{
public virtual List<Addresses> Addresses { get; set; }
}
public class Addresses
{
[Key]
public int AddressID { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public bool IsDefault { get; set; }
public int SerialNo { get; set; }
public virtual List<Contacts> Contacts { get; set; }
public int CustomerID { get; set; }
public virtual Customer Customer { get; set; }
}
public class Contacts
{
[Key]
public int ContactID { get; set; }
public string Phone { get; set; }
public string Fax { get; set; }
public bool IsDefault { get; set; }
public int SerialNo { get; set; }
public int AddressID { get; set; }
public virtual Addresses Customer { get; set; }
}
Full Working code
using (var db = new TestDBContext())
{
//db.Database.Log = s => MyLogger.Log("EFApp", s);
var existingCustomer = db.Customer
.Include(a => a.Addresses.Select(x => x.Contacts))
.FirstOrDefault(p => p.CustomerID == 5);
existingCustomer.FirstName = "Test Customer123";
existingCustomer.Addresses.Where(a => a.AddressID == 5).ToList().ForEach(r => db.Addresses.Remove(r));
existingCustomer.Addresses.Where(a => a.AddressID == 5).SelectMany(ad => ad.Contacts).Where(c=> c.ContactID==5).ToList().ForEach(r => db.Contacts.Remove(r));
Addresses oAdrModel = new Addresses();
oAdrModel.Address1 = "test xxx";
oAdrModel.Address2 = "test xxx";
oAdrModel.SerialNo = 3;
oAdrModel.IsDefault = true;
oAdrModel.CustomerID = 5;
db.Addresses.Add(oAdrModel);
db.SaveChanges();
int CurAddressID = oAdrModel.AddressID;
Contacts ContactModel = new Contacts();
ContactModel.Phone = "XX-1111111-33";
ContactModel.Fax = "XX-1-1111111";
ContactModel.SerialNo = 4;
ContactModel.IsDefault = true;
ContactModel.AddressID = CurAddressID;
db.Contacts.Add(ContactModel);
db.SaveChanges();
}
Your problem isn't directly related to EF, but to Enumerables.
You can't call Remove, Add or anything else that modifies the collection on a collection that you are currently enumerating. (Which is why the error message says "Collection was modified; enumeration operation may not execute.")
This part for example:
foreach (var CustContacts in existingAddress.Contacts.Where(a => a.ContactID == 5))
{
CurrentContacts = CustContacts;
existingAddress.Contacts.Remove(CurrentContacts);
}
You are enumerating Contacts and within the loop you are removing contacts. A simple workaround is to call ToList (as you have done in the outer loop) to make sure you are working with a different Enumeration.
e.g.
foreach (var CustContacts in existingAddress.Contacts.Where(a => a.ContactID == 5).ToList())
{
CurrentContacts = CustContacts;
existingAddress.Contacts.Remove(CurrentContacts);
}
I'm not entirely sure what you are trying to achieve but from the looks of it you might be better off if you had a clean implementation of cascade delete in your database (remove related/connected entries automatically).

How can I create set contain id record in first set equal id record in second set?

In database I have two tables:
public partial class PersonOne
{
public int id { get; set; }
public string name { get; set; }
public string surname { get; set; }
}
public partial class PersonTwo
{
public int id { get; set; }
public string firstname { get; set; }
public string lastname { get; set; }
}
I would like to fill my set:
public class PersonOnePersonTwo
{
public int PersonOneId { get; set; }
public int PersonTwoId { get; set; }
}
where PersonOne.name == PersonTwo.firstname && PersonOne.surname == PersonTwo.lastname but I have no idea how I can do that - because below code isn't efficient and is so slow:
List<PersonOne> personOneList = new List<PersonOne>();
List<PersonTwo> personTwoList = new List<PersonTwo>();
List<PersonOnePersonTwo> personOnePersonTwoList = new List<PersonOnePersonTwo>();
foreach (PersonOne personOne in personOneList)
{
foreach(PersonTwo personTwo in personTwoList.Where(x => x.firstname == personOne.name && x.lastname == personOne.surname).ToList())
{
personOnePersonTwoList.Add(new PersonOnePersonTwo
{
PersonOneId = personOne.id,
PersonTwoId = personTwo.id
});
}
};
Try this:
var result = personOneList.Join
(
personTwoList,
person1 => new { Key1 = person1.Name, Key2 = person1.Surname },
person2 => new { Key1 = person2.FirstName, Key2 = person2.LastName },
(person1, person2) => new PersonOnePersonTwo { PersonOneId = person1.Id, PersonTwoId = person2.Id }
).ToList();
I would go with:
var personOnePersonTwoList = new List<PersonOnePersonTwo>();
foreach (var personOne in personOneList)
{
personOnePersonTwoList = personTwoList.Where(x => x.firstname.Equals(personOne.name, StringComparison.OrdinalIgnoreCase) &&
x.lastname.Equals(personOne.surname, StringComparison.OrdinalIgnoreCase))
.Select(x => new PersonOnePersonTwo {PersonOneId = personOne.id, PersonTwoId = x.id}).ToList();
};
As a side note: it's more convinient to use Equals when comparing strings.

Categories

Resources