I am trying to add a range of values from four distinct list of objects to a list. This is the code I have to add all the items from one list of objects...
var formList = new List<FormList>();
formList = forms.LimitedWillForms.Select(a => new FormList()
{
DateCreated = a.CreationDate,
FormId = a.Id,
FormType = a.FormType,
Submitted = a.SubmissionDate != null
}).ToList();
I am trying to not just add from the forms.LimitedWillForms list, but also from the forms.FullWillForms, and the forms.FullWillForms2, and the forms.FullWillForms3 too, adding the same parameters. This seems to work to add selected parameters from the form to the list.
I am not sure of the most efficient way to use linq to add selected parameters from all four lists to the formList. Can anyone help?
Since the lists contain objects of different types your best option would be to add an common interface to all the types for the common properties.
public interface IRecord
{
DateTime DateCreated {get;set;}
int FormId {get;set;}
....
}
You can then do:
var formList = forms.LimitedWillForms
.Cast<IRecord>
.Concat(forms.FullWillForms)
.Concat(forms.FullWillForms2)
.Concat(forms.FullWillForms3)
.Select(x => new FormList()
{
DateCreated = x.CreationDate,
FormId = x.Id,
FormType = x.FormType,
Submitted = x.SubmissionDate != null
}).ToList();
If you can live with just getting back a list if IRecord instead of FormList you can actually skip the last select.
If that is not possible you would need to select the properties from each collection.
var formList = forms.LimitedWillForms.Select(x => new FormList()
{
DateCreated = x.CreationDate,
FormId = x.Id,
FormType = x.FormType,
Submitted = x.SubmissionDate != null
}).Concat(
forms.FullWillForms.Select(x => new FormList()
{
DateCreated = x.CreationDate,
FormId = x.Id,
FormType = x.FormType,
Submitted = x.SubmissionDate != null
}
).Concat(...).ToList();
Try this:
var formList = forms.LimitedWillForms.Select(a => new FormList
{
DateCreated = a.CreationDate,
FormId = a.Id,
FormType = a.FormType,
Submitted = a.SubmissionDate != null
})
.Union(forms.FullWillForms.Select(a => new FormList
{
DateCreated = a.CreationDate,
FormId = a.Id,
FormType = a.FormType,
Submitted = a.SubmissionDate != null
}))
.Union(forms.FullWillForms2.Select(a => new FormList
{
DateCreated = a.CreationDate,
FormId = a.Id,
FormType = a.FormType,
Submitted = a.SubmissionDate != null
}))
.Union(forms.FullWillForms3.Select(a => new FormList
{
DateCreated = a.CreationDate,
FormId = a.Id,
FormType = a.FormType,
Submitted = a.SubmissionDate != null
})).ToList();
Related
Attempting to return the below 2 lists into something I can then query against.
var people = (from c in _context.FollowingPeople
select new Models.Following.FollowingModel
{
Id = c.Id,
MediaTypeId = c.MediaTypeId,
Title = c.Title,
ClientId = c.ClientId,
Person = (from p in _context.SocialMediaPeople
where p.Id == c.SocialMediaId
select new Models.SocialMediaPeople
{
Id = p.Id,
Photo = p.Photo
}).FirstOrDefault()
});
var generic = (from c in _context.FollowingGeneric
select new Models.Following.FollowingModel
{
Id = c.Id,
MediaTypeId = c.MediaTypeId,
Title = c.Title,
ClientId = c.ClientId,
Person = null
});
var temp = people.Concat(generic).ToList();
//var data = temp.AsQueryable();
if (!string.IsNullOrEmpty(filter))
{
data = data.Where(filter);
}
data = data.Where(x => x.ClientId == ClientId);
return await data
.GetPaged(page, pageSize);
I have tried join, concat, even Zip but it results in various errors such as
(Unable to translate set operation after client projection has been applied. Consider moving the set operation before the last 'Select' call.)
So I finally got this working, the trick is to not perform any queries on the data until AFTER the concat. Th below works...
var queryA =
from c in _context.Set<FollowingPeople>()
select new Models.Following.FollowingModel
{
Id = c.Id,
MediaTypeId = c.MediaTypeId,
Title = c.Title,
ClientId = c.ClientId
};
var queryB =
from c in _context.Set<FollowingGeneric>()
select new Models.Following.FollowingModel
{
Id = c.Id,
MediaTypeId = c.MediaTypeId,
Title = c.Title,
ClientId = c.ClientId
};
var queryC =
from c in _context.Set<FollowingPublication>()
select new Models.Following.FollowingModel
{
Id = c.Id,
MediaTypeId = c.MediaTypeId,
Title = c.Title,
ClientId = c.ClientId
};
var data = (from v in queryA.Union(queryB).Union(queryC)
select new Models.Following.FollowingModel
{
Id = v.Id,
MediaTypeId = v.MediaTypeId,
Title = v.Title,
ClientId = v.ClientId,
})
.AsNoTracking()
.AsQueryable();
data = data.Where(x => x.ClientId == ClientId);
return await data.GetPaged(page, pageSize);
I have two tables with similar data for body insurance and third party car insurance ... I have used enum in the model to separate the insurances and I want to do the creation operation for it .... There are two modes for each insurance. One case when that car does not have insurance yet and the second case when we want to extend it.
I wrote this code to create the form, but it encounters the following error
I also get an error on the name of the Create function.error = not all code paths return a value.
Please advise
public async Task<IActionResult> Create(int id, int type)
{
InsuranceViewModel model;
ViewBag.Type = type;
var companies = await _context.InsuranceCompany
.Where(e => e.IsActice)
.ToListAsync();
ViewData["CompanyList"] = new SelectList(companies, "Id", "CompanyName");
if ((InsuranceType)type == InsuranceType.Body)
{
var bodyInsurance = await _context.BodyInsurance
.Include(e => e.InsuranceCompany)
.FirstOrDefaultAsync(e => e.Id == id);
if (bodyInsurance == null)
{
model = new InsuranceViewModel
{
CompanyId = bodyInsurance.InsuranceCompanyId,
CompanyName = bodyInsurance.InsuranceCompany.CompanyName,
InsuranceType = InsuranceType.Body,
IssueDate = new DateTime(bodyInsurance.IssueDate).Ticks,
ExpireDate = new DateTime(bodyInsurance.ExpireDate).Ticks,
VehicleInformationId = id
};
}
else
{
var lastBody = await _context.BodyInsurance.Include(e => e.InsuranceCompany)
.Where(e => e.VehicleInformationId == id)
.OrderBy(e => e.ExpireDate)
.LastAsync();
model = new InsuranceViewModel
{
ExpireDate = new DateTime(lastBody.ExpireDate).AddYears(1).AddDays(1).Ticks,
CompanyId = lastBody.InsuranceCompanyId,
CompanyName = lastBody.InsuranceCompany.CompanyName,
InsuranceType = InsuranceType.Body,
IssueDate = new DateTime(lastBody.ExpireDate).AddDays(1).Ticks,
VehicleInformationId = id
};
}
}
else
{
if ((InsuranceType)type == InsuranceType.Thirdpart)
{
var thirdParty = await _context.ThirdPartyInsurance
.Include(e => e.InsuranceCompany)
.FirstOrDefaultAsync(e => e.Id == id);
if (thirdParty == null)
{
model = new InsuranceViewModel
{
CompanyId = thirdParty.InsuranceCompanyId,
CompanyName = thirdParty.InsuranceCompany.CompanyName,
InsuranceType = InsuranceType.Body,
IssueDate = new DateTime(thirdParty.IssueDate).Ticks,
ExpireDate = new DateTime(thirdParty.ExpireDate).Ticks,
VehicleInformationId = id
};
}
else
{
var lastThirdParty = await _context.ThirdPartyInsurance.Include(e => e.InsuranceCompany)
.Where(e => e.VehicleInformationId == id)
.OrderBy(e => e.ExpireDate)
.LastAsync();
model = new InsuranceViewModel
{
ExpireDate = new DateTime(lastThirdParty.ExpireDate).AddYears(1).AddDays(1).Ticks,
CompanyId = lastThirdParty.InsuranceCompanyId,
CompanyName = lastThirdParty.InsuranceCompany.CompanyName,
InsuranceType = InsuranceType.Body,
IssueDate = new DateTime(lastThirdParty.ExpireDate).AddDays(1).Ticks,
VehicleInformationId = id
};
}
}
return View(model);
}
I have a result coming back from a LINQ statement that looks like this:
Id dataId dataVal
A 1 1000
A 2 2000
A 3 3000
A 3 3001
A 3 3002
What I'd like is to just get the 1st item (dataId = 3 and dataVal = 3000)
Here is my query that is generating the above result:
var myIds = myList
.Where(a => ListIds.Contains(a.dataId))
.Select(x=> new
{
Id = x.Id,
DataId = x.dataId,
DataValue = x.DataValue
}).ToList().Distinct();
Do I need to do some grouping or is there an easier way?
Group your items by dataId, and then select first item from each group:
var myIds = (from a in myList
where ListIds.Contains(a.dataId)
group a by a.dataId into g
let firstA = g.OrderBy(x => x.DataValue).First()
select new {
Id = firstA.Id,
DataId = g.Key,
DataValue = firstA.DataValue
}).ToList();
Or with extension methods (it returns first item in original order):
var myIds = myList
.Where(a => ListIds.Contains(a.dataId))
.GroupBy(a => a.dataId)
.Select(g => new
{
Id = g.First().Id,
DataId = g.Key,
DataValue = g.First().DataValue
}).ToList();
Use .FirstOrDefault() after the Select
var myIds = myList
.Where(a => ListIds.Contains(a.dataId))
.Select(x=> new
{
Id = x.Id,
DataId = x.dataId,
DataValue = x.DataValue
}).FirstOrDefault();
I have the following code:
public class Report
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Sales { get; set; }
}
var result = myItems.GroupBy(x => new { Id = x.Id, Name = x.Name }).Select(x => new Report { Id = x.Key.Id, Name = x.Key.Name });
foreach (var item in result)
{
item.Sales = anotherColletion.FirstOrDefault(x => x.Id == item.Id).Sales;
}
I am unable to set the sales property to any value this way. Even if I try:
foreach (var item in result)
{
item.Sales = 50;
}
However, if I set the property using the following code it works:
var result = myItems.GroupBy(x => new { Id = x.Id, Name = x.Name }).Select(x => new Report { Id = x.Key.Id, Name = x.Key.Name, Sales = 50 });
Is this by design?
The problem is that LINQ queries are lazy ("deferred execution"). You are setting the property on each result of the query in the foreach loop, but these results will essentially disappear into thin air.
When you enumerate the results of the query again after your foreach (which you haven't shown us), the query is re-executed and the results recreated, effectively undoing your changes. Remember that the query is just a specification for how to produce the results, not the results themselves.
A simple fix is to materialize the query into a collection first.
var result = myItems.GroupBy(x => new { Id = x.Id, Name = x.Name })
.Select(x => new Report { Id = x.Key.Id, Name = x.Key.Name })
.ToList();
Your foreach will then end up mutating the elements of an in-memory collection rather than the results of a lazy query, and will therefore be visible downstream.
Personally though, consider setting the property in the query itself:
var result = myItems.GroupBy(x => new { Id = x.Id, Name = x.Name })
.Select(x => new Report
{
Id = x.Key.Id,
Name = x.Key.Name,
Sales = anotherCollection.First(a => a.Id == x.KeyId)
.Sales
});
Thomas,
The var results you are using is just a query, when you iterate over it, in the foreach loop, you are generating a new report object but it is not 'stored' anywhere.
Add the ToArray() or ToList() to the end of the query to fix the issue:
var result = myItems.GroupBy(x => new { Id = x.Id, Name = x.Name }).Select(x => new Report { Id = x.Key.Id, Name = x.Key.Name }).ToList();
Amir.
I have a list of objects, those objects may or may not have contact info:
// Join contact
query = query.Join(
(new ContactRepository(this.Db)).List().Where(x => x.IsMainContact),
x => new { x.ListItem.ContentObject.LoginId },
y => new { y.LoginId },
(x, y) => new ListItemExtended<ListItemFirm>
{
City = y.City,
State = y.State,
Country = y.Country
});
This does inner join on 'LoginId'. But I need an outter join so that if contact info does not exists for a given LoginId it will be empty.
Please help
thanks
You should execute outer join manually:
var contacts = (new ContactRepository(this.Db)).List();
query.Select(item =>
{
var foundContact = contacts.FirstOrDefault(contact => contact.Id == item.Id);
return new ListItemExtended<ListItemFirm>()
{
Id = item.Id,
City = foundContact != null ? foundContact.City : null,
State = foundContact != null ? foundContact.State : null,
Country = foundContact != null ? foundContact.Country : null,
};
})
But remember that if your Contact item is struct - checking for null isn't proper way. Use Any() operator instead of FirstOrDefault().