Creating an Object List from another List Object LINQ Lambda - c#

I am trying to add certain objects to another object. But I am getting an error in the Options section. I am quite simply trying to add certain stuff out of one object and into another.
Here is what my code looks like..
var responses = new Responses();
form.Questions.ForEach(
q => responses.Questions.Add(new Models.Question()
{
QuestionId = Convert.ToInt32(q.Id),
Value = q.SingleAnswer,
Options = q.Options.ForEach( o => q.Options.Add(
new Option // <----FAILING HERE!!!!!!!!!!!!
{
OptionId = 1,
Value = "test"
}
))
})
);
The error is
Argument type 'Web.Models.Option' is not assignable to parameter type QuestionOptionViewModel
MODELS:
public class Responses
{
public List<Question> Questions { get; set; }
}
public class Question
{
public int QuestionId { get; set; }
public string Value { get; set; }
public List<Option> Options { get; set; }
}
public class Option
{
public int OptionId { get; set; }
public string Value { get; set; }
}
public class QuestionOptionViewModel
{
public int? Id { get; set; }
public string Text { get; set; }
public string QuestionType { get; set; }
[RequiredIf("QuestionType", "text", ErrorMessage = "Required Field")]
public string Value { get; set; }
[RequiredIf("QuestionType", "checkbox", ErrorMessage = "Required Field")]
public bool IsChecked { get; set; }
}
public class QuestionViewModel
{
public int? Id { get; set; }
public string QuestionType { get; set; }
public string SubType { get; set; }
public string Text { get; set; }
public int SortOrder { get; set; }
public bool IsHidden { get; set; }
[RequiredIf("QuestionType", "singleAnswer", ErrorMessage = "Reqired Field")]
public string SingleAnswer { get; set; }
[RequiredIf("QuestionType", "radio", ErrorMessage = "Radio Reqired")]
public int? SelectedRadio { get; set; }
[RequiredIf("QuestionType", "select", ErrorMessage = "Selection Reqired")]
public int? SelectedSelect { get; set; }
public bool CheckboxError { get; set; }
public List<QuestionOptionViewModel> Options { get; set; }
}

Hopefully this isn't too misguided but I think you're going about this all wrong. You want to do a Select and assign the result to the questions property in responses. Here's a basic example;
var responses = new Responses();
responses.Questions = form.Questions.Select(
q => new Models.Question()
{
QuestionId = Convert.ToInt32(q.Id),
Value = q.SingleAnswer,
Options = q.Options.Select(o =>
new Option
{
OptionId = (int) o.Id,
Value = o.Value
}).ToList()
}).ToList();
I edited your code rather quickly so there is some potential that won't work as is (didn't compile or anything). But basically you use Select for projection, return a List<Question> and assign it to the Questions property. Don't try to do the adds in place. Besides that you never initialized the Questions list so even if that code compiled you'd get a NullReferenceException. Again, there are likely other problems with your code but I think you're fundamentally misusing ForEach when Select is actually the correct operation.

There are two issues here. One you are trying to change the collection you are iterating over with your ForEach. And second you are trying to assign the result of that ForEach. Instead you should use a Select and ToList to create a list to assign to Options. If you change
Options = q.Options.ForEach( o => q.Options.Add(
new Option
{
OptionId = 1,
Value = "test"
}
))
to
Options = q.Options.Select(
new Option
{
OptionId = 1,
Value = "test"
}
).ToList()
it should work

Related

EF Core return specific columns from child tables

I don't want to use .include to get the entire child tables. I just need select columns.
public class ProjectTypeDTO {
public string Type { get; set; }
}
public class CourseDTO {
public string CourseCode { get; set; }
public string CourseTitle { get; set; }
}
public class ProjectDTO {
public int Id { get; set; }
public ProjectTypeDTO ProjectType { get; set; }
public CourseDTO Course { get; set; }
public string StartTerm { get; set; }
public DateTime SignOff { get; set; }
public DateTime StartDateTime { get; set; }
}
[HttpGet("getallprojects")]
public IActionResult GetAllProjects()
{
var projects = _context.Projects
.Select(p => new ProjectDTO
{
Id = p.Id,
ProjectType = { Type = p.ProjectType.Type },
Course = { CourseCode = p.Course.CourseCode, CourseTitle = p.Course.CourseTitle },
StartTerm = p.StartTerm,
SignOff = p.SignOff,
StartDateTime = p.StartDateTime,
}).ToList();
return Ok(projects);
}
This is throwing a "NotImplementedException: The method or operation is not implemented." error.
I've tested it as an anonymous function and it works.
var projects = _context.Projects
.Select(p => new
{
p.Id,
p.ProjectType.Type,
p.SignOff,
p.StartDateTime,
p.Course.CourseCode,
p.Course.CourseTitle,
p.StartTerm
}).ToList();
An anonymous type won't work for my app, since I need to be able to make changes to this data before it gets returned.
Based on other examples I've seen here and other sites, this looks correct. Could it be a bug?
I haven't seen that syntax for sub-objects before. eg:
ProjectType = { Type = p.ProjectType.Type }
I believe that should be:
ProjectType = new ProjectTypeDTO{ Type = p.ProjectType.Type }

ASP.NET MVC 5 Edit Action - How to write to Multiple DB Tables/Models

Is there any way to somehow combine the data from two models and THEN map them both to the same viewModel in the context of an edit action?
I have never had to update several tables at once in an edit action in ASP.NET MVC with Entity Framework 6.1.3. This is the layout:
I have a DB table called "Address" which has fields for StreetNumber, StreetName, City, State, ZipCode. It has a one-to-one relationship with another table called Bars. As in, a bar can only have one address and one address can only have one bar.
Because I am storing this data in two separate tables, I am having a very difficult time trying to successfully implement an Edit action which takes data from one form (BarForm) and should update both the Bar and Address database tables. See my code:
BarController
public ActionResult Edit(int id)
{
var bar = _context.Bars.SingleOrDefault(m => m.Id == id);
var address = _context.Addresses.SingleOrDefault(a => a.BarId == id);
//Make sure that the id actually exists:
if (bar == null)
{
return HttpNotFound();
}
var viewModel = Mapper.Map<Bar, BarFormViewModel>(bar, new BarFormViewModel());
if (address == null)
{
address = new Address();
}
Mapper.Map<Address, BarFormViewModel>(address, viewModel);
viewModel.IsNew = false;
return View("BarForm", viewModel);
}
[ValidateAntiForgeryToken]
public ActionResult Save(BarFormViewModel bar)
{
if (!ModelState.IsValid)
{
var viewModel = Mapper.Map<BarFormViewModel, BarFormViewModel>(bar, new BarFormViewModel());
viewModel.IsNew = false;
return View("BarForm", viewModel);
}
if (bar.Id == 0)
{
var newbar = Mapper.Map<BarFormViewModel, Bar>(bar);
newbar.LastUpdated = DateTime.UtcNow;
_context.Bars.Add(newbar);
var addressToAdd = Mapper.Map<BarFormViewModel, Address>(bar);
_context.Addresses.Add(addressToAdd);
}
else
{
var barInDb = _context.Bars.Single(b => b.Id == bar.Id);
var addressInDb = _context.Addresses.Single(a => a.BarId == bar.Id);
Mapper.Map<BarFormViewModel, Bar>(bar, barInDb);
Mapper.Map<BarFormViewModel, Address>(bar, addressInDb);
}
_context.SaveChanges();
return RedirectToAction("Index", "Bar");
}
Domain Models:
public class Bar
{
public int Id { get; set; }
public string Name { get; set; }
[Required]
public string GooglePlaceId { get; set; }
public string SundayDiscounts { get; set; }
public string MondayDiscounts { get; set; }
public string TuesdayDiscounts { get; set; }
public string WednesdayDiscounts { get; set; }
public string ThursdayDiscounts { get; set; }
public string FridayDiscounts { get; set; }
public string SaturdayDiscounts { get; set; }
[Display(Name = "Last Updated")]
public DateTime LastUpdated { get; set; }
}
public class Address
{
public int Id { get; set; }
public int? Number { get; set; }
public string StreetName { get; set; }
public string City { get; set; }
public string State { get; set; }
[Required]
public int ZipCode { get; set; }
public Bar Bar { get; set; }
public int BarId { get; set; }
}
View Model which includes both Address and Bar properties:
{
public class BarFormViewModel
{
public int? Id { get; set; }
public string Name { get; set; }
[Required]
[Display(Name = "Google Place ID")]
public string GooglePlaceId { get; set; }
[Display(Name = "Sunday Happy Hour Info:")]
public string SundayDiscounts { get; set; }
[Display(Name = "Monday Happy Hour Info:")]
public string MondayDiscounts { get; set; }
[Display(Name = "Tuesday Happy Hour Info:")]
public string TuesdayDiscounts { get; set; }
[Display(Name = "Wednesday Happy Hour Info:")]
public string WednesdayDiscounts { get; set; }
[Display(Name = "Thursday Happy Hour Info:")]
public string ThursdayDiscounts { get; set; }
[Display(Name = "Friday Happy Hour Info:")]
public string FridayDiscounts { get; set; }
[Display(Name = "Saturday Happy Hour Info:")]
public string SaturdayDiscounts { get; set; }
[Display(Name = "Last Updated")]
public DateTime? LastUpdated { get; set; }
//Address Model Info
public Address Address { get; set; }
public int? AddressId { get; set; }
[RegularExpression("([1-9][0-9]*)", ErrorMessage = "Must be a number")]
public int? Number { get; set; }
public string StreetName { get; set; }
public string City { get; set; }
public string State { get; set; }
[Required]
public int? ZipCode { get; set; }
public bool IsNew { get; set; }
}
The problem here is that I am getting an empty AddressId with this setup, which is causing an exception when the Save action gets run. This is because the BarForm view is getting passed a ViewModel which has been mapped from a Bar object and the Bar domain model actually has no Address information in it, since it is not the Address model/table.
Is there any way to somehow combine the data from both the Address and Bar models and THEN map them both to the same viewModel?
I keep getting a Sequence Contains no Elements error for this line in the Save action:
var addressInDb = _context.Addresses.Single(a => a.Id == bar.AddressId);
I also tried:
var addressInDb = _context.Addresses.Single(a => a.BarId == bar.Id);
Neither work. I understand what the error is saying and have also checked the actual HTML for my hidden Addressid field and it is blank... See code in my BarForm View:
#Html.HiddenFor(m => m.Id)
#Html.HiddenFor(m => m.AddressId)
#Html.AntiForgeryToken()
Remove the new BarFormViewModel() as the second parameter in your mapping calls as it is not necessary.
In your post action, inside your if statement that checks if the ModelState is valid and if bar.Id == 0, bar is already a view model, so no need to mapping.
And when you create your AutoMapper mapping, you must create a custom property mapping because the Address.Id property will not map automatically to the AddressId property as the name is not the same.
AutoMapper.Mapper.CreateMap<Address, BarFormViewModel>()
.ForMember(dest => dest.AddressId, o => o.MapFrom(source => source.Id));
And then do the same for the inverse mapping.

MVC4: Retrieving a related list with Entity and casting it as List<> or IEnum<> for View Model

This a simple project where users can search for job postings by area of expertise. The relationship between Areas and Postings are Many-to-many. I seem to be able to get to the very last part of retrieving the correctly filtered list, but getting back into the view model keeps giving me different errors:
ViewModel:
public class AreaOfertasViewModel
{
public Oferta UnaOferta { get; set; }
public SelectList AreasTrabajo { get; set; }
public IEnumerable<Oferta> Ofertas { get; set; }
public int idArea { get; set; }
public AreaOfertasViewModel()
{
this.UnaOferta = UnaOferta;
this.Ofertas = new List<Oferta>();
cargarAreas();
}
private void cargarAreas()
{
PostulaOfertaContext db = new PostulaOfertaContext();
this.AreasTrabajo = new SelectList(db.Areas, "areaId", "Area");
}
}
}
Controller:
public ActionResult SearchXArea()
{
return View(new AreaOfertasViewModel());
}
[HttpPost]
public ActionResult SearchXArea(AreaOfertasViewModel aovm)
{
int id = aovm.idArea;
PostulaOfertaContext db = new PostulaOfertaContext();
var area = db.Areas.Where(c => c.areaId == id);
var ofertas = from c in db.Ofertas.Where(r => r.AreaTrabajo == area)
select c;
aovm.Ofertas = (IEnumerable<Oferta>)ofertas.ToList();
return View(aovm);
}
The line giving me issues is
aovm.Ofertas = (IEnumerable)ofertas.ToList();
I've tried List<> for Ofertas, and I've tried leaving it as .ToList() without casting, and casting it as different things, but it gives me errors about not being able to cast it, and "Cannot compare elements of type 'System.Collections.Generic.List`1'. Only primitive types, enumeration types and entity types are supported."
What's the solution here?
Model for AreaTrabajo:
public class AreaTrabajo
{
[Key]
public int areaId { get; set; }
public string Area { get; set; }
public virtual List<Oferta> oferta { get; set; }
}
Model for Oferta:
public class Oferta
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public string Titulo { get; set; }
[Required]
public DateTime Vencimiento { get; set; }
[Required]
public string Cargo { get; set; }
[Required]
public int HorarioComienzo { get; set; }
[Required]
public int HorarioFin { get; set; }
[Required]
public string DescripcionTareas { get; set; }
public int Remuneracion { get; set; }
[Required]
public int RangoEdadMin { get; set; }
[Required]
public int RangoEdadMax { get; set; }
public string TipoFormacion { get; set; }
public string Idiomas { get; set; }
public string Competencias { get; set; }
public string OtrosEstudios { get; set; }
public string Estado { get; set; }
public virtual List<AreaTrabajo> AreaTrabajo { get; set; }
public virtual TipoContrato TipoContrato { get; set; }
public virtual Empresa Empresa { get; set; }
public virtual List<Postulante> Postulantes { get; set; }
}
Answer
[HttpPost]
public ActionResult SearchXArea(AreaOfertasViewModel aovm)
{
int id = aovm.idArea;
PostulaOfertaContext db = new PostulaOfertaContext();
var area = db.Areas.Where(c => c.areaId == id).FirstOrDefault();
var ofertas = db.Ofertas.Where(s => s.AreaTrabajo.All(e => e.areaId == area.areaId)).ToList();
aovm.Ofertas = ofertas;
return View(aovm);
}
Sorry if my question wasn't clear enough. I needed to filter out from the many-to-many relationship, and this solved it.
You are getting an error because the actual sql is executed when you call tolist(). The error is in your sql because you are comparing AreaTrabago to a list.
[HttpPost]
public ActionResult SearchXArea(AreaOfertasViewModel aovm)
{
int id = aovm.idArea;
PostulaOfertaContext db = new PostulaOfertaContext();
var area = db.Areas.Where(c => c.areaId == id).FirstOrDefault();
var ofertas = db.Ofertas.Where(s => s.AreaTrabajo.All(e => e.areaId == area.areaId)).ToList();
aovm.Ofertas = ofertas;
return View(aovm);
}
Sorry if my question wasn't clear enough. I couldn't get the many-to-many relationship, and this solved the filtering problem perfectly.

DropDownListFor Properties of Collection in ViewModel

I am new to ASP.NET MVC and was/am not sure exactly how to word my problem. I have to create a page where the user can add a list of multiple collateral items to a loan application. Each "row" for each collateral items needs several Dropdownlist to select the type of collateral, its class etc. The page is based on a ViewModel:
public class CollateralViewModel
{
public Guid LoanApplicationId { get; set; }
public IEnumerable<CollateralRowViewModel> Collateral { get; set; }
}
The IEnumerable Collateral gets the following:
public class CollateralRowViewModel
{
public Guid Id { get; set; }
public Guid LoanApplicationId { get; set; }
public IEnumerable<SelectListItem> CollateralClass { get; set; }
public IEnumerable<SelectListItem> CollateralType { get; set; }
public Guid SelectedCollateralType { get; set; }
public Guid SelectedCollateralClass { get; set; }
[DataType(DataType.MultilineText)]
public string Description { get; set; }
public decimal? MarketValue { get; set; }
public decimal? PriorLiens { get; set; }
public decimal? AdvanceRate { get; set; }
public string GrantorFirstName { get; set; }
public string GrantorMiddleName { get; set; }
public string GrantorLastName { get; set; }
}
My Controller looks like this:
public async Task<ActionResult> Create(CollateralViewModel collateralViewModel)
{
var collateralServiceProxy = base.ServiceProvider.CollateralServiceProxy;
var collateralTypes = await GetCollateralTypesByClass(Guid.NewGuid());
var selectedCollateral = collateralViewModel.Collateral.Select(collateral => new Collateral()
{
Id = collateral.Id,
LoanApplicationId = collateral.LoanApplicationId,
CollateralTypeId = collateral.SelectedCollateralType,
Description = collateral.Description,
GrantorFirstName = collateral.GrantorFirstName,
GrantorMiddleName = collateral.GrantorMiddleName,
GrantorLastName = collateral.GrantorLastName,
PriorLiens = collateral.PriorLiens,
MarketValue = collateral.MarketValue
});
foreach (var collateral in selectedCollateral)
{
await collateralServiceProxy.PutCollateralAsync(collateral);
}
return View(collateralViewModel);
}
private async Task<IEnumerable<SelectListItem>> GetCollateralClasses()
{
var collateralServiceProxy = base.ServiceProvider.CollateralServiceProxy;
var collateralClasses = await collateralServiceProxy.GetAllCollateralClassesAsync();
if (collateralClasses == null)
{
return new List<SelectListItem>();
}
return collateralClasses.ToSelectList();
}
private async Task<IEnumerable<SelectListItem>> GetCollateralTypesByClass(Guid collateralClassId)
{
var allCollateralTypes = await GetAllCollateralTypes();
var selectedCollateralTypes = allCollateralTypes.Where(collateralType => Guid.Parse(collateralType.Value).Equals(collateralClassId));
return selectedCollateralTypes;
}
When I try to use #Html.DropDownListFor(model=>model.Collateral.CollateralClasses) I cannot because CollateralClasses is unavailable. I type "(model.Collateral." and the properties aren't there. What am I doing wrong here?
Any help is greatly appreciated!!
Please check you dropdownlistfor syntex. I think that may be the issue (because you have not specified the error).Please check the syntex
#Html.DropDownListFor(m => m.ContribType,
new SelectList(Model.ContribTypeOptions,
"ContribId", "Value",
Model.ContribTypeOptions.First().ContribId))
so you may try it like this. In your first place "valueItRepresent", it should be the property for which the dropdown is for
#Html.DropDownListFor(model => model.valueItRepresent, model.Collateral.FirstOrDefault().CollateralClasses‌ as SelectList, "Select")
The issue is your dropdownlist not populated when rendering the UI. You have to properly populate dropdownlist before render data.This can be done in several ways, but I would recommend reading below article.
This article provide solution for your question
http://odetocode.com/blogs/scott/archive/2013/03/11/dropdownlistfor-with-asp-net-mvc.aspx
Hope this helps.

EF4.1 - Attribute Evaluating to null at runtime

I'm using EF4.1 code first to create a simple database app with SQL CE 4 backend. I have a Product class and a CallItem class defined as so:
class CallItem
{
public int id { get; set; }
public float discount { get; set; }
public virtual Product Product { get; set; }
}
class Product
{
public int id { get; set; }
public decimal BaseCost { get; set; }
public int UnitSize { get; set; }
public bool isWasteOil { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Ingredients { get; set; }
}
edit - When I am creating a collection of CallItems using a LINQ query, I cannot access the attributes of the Product attached to each CallItem, eg
var callItems = from ci in context.CallItems select ci;
foreach(CallItem callItem in callItems)
{
RunSheet nrs = new RunSheet();
nrs.prodCode = callitem.Product.Code;
}
Interrogating the database shows that Productid in CallItems is being populated. However, the following line generates a NullReferenceException during run time:
nrs.prodCode = callitem.Product.Code;
Because callitem.Product is evaluating to null. Is this something to do with lazy loading and if so how can I resolve the issue?
RunSheet is another class, nrs is an instance whose attribute 'prodCode' I want to populate with the CallItem's Product's code.
Thanks!
From that code what you've showed it should work. Have you tried explicit loading?
var callItems = from ci in context.CallItems.Include(c => c.Product) select ci;
foreach(CallItem callItem in callItems)
{
RunSheet nrs = new RunSheet();
nrs.prodCode = callitem.Product.Code;
}
public class CallItem
{
public int Id { get; set; }
public float Discount { get; set; }
public virtual Product Product { get; set; }
}
public class Product
{
public int Id { get; set; }
public decimal BaseCost { get; set; }
public int UnitSize { get; set; }
public bool IsWasteOil { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Ingredients { get; set; }
}
using (var context = new StackOverFlowContext())
{
var p = new Product
{
Id = 1,
BaseCost = 200,
Code = "Hola",
Description = "Soe description",
Ingredients = "Some ingredients",
IsWasteOil = true,
Name = "My Product",
UnitSize = 10
};
var item = new CallItem
{
Id = 101,
Discount = 10,
Product = p
};
context.CallItems.Add(item);
context.SaveChanges();
var result = from temp in context.CallItems
select temp;
Console.WriteLine("CallItem Id"+result.First().Id);
Console.WriteLine("ProductId"+result.First().Product.Id);
}
I wrote the above code with the following output
CallItemId 1
ProductId 1
The sql Profiler showed this
SELECT TOP (1)
[c].[Id] AS [Id],
[c].[Discount] AS [Discount],
[c].[Product_Id] AS [Product_Id]
FROM [dbo].[CallItems] AS [c]
It was too long for a comment ,so i put it here .

Categories

Resources