I have two class. PRODUCT comes from Entity Framework, and Product in Domain solution: Here are the details:
PRODUCT class (source):
namespace SportsStore.Domain
{
using System;
using System.Collections.Generic;
public partial class PRODUCT
{
public int PRODUCT_ID { get; set; }
public string PRODUCT_NAME { get; set; }
public string PRODUCT_DESCRIPTION { get; set; }
public decimal PRODUCT_PRICE { get; set; }
public string PRODUCT_CATEGORY { get; set; }
}
}
Product class (destination):
namespace SportsStore.Domain.Entities
{
public class Product
{
[HiddenInput(DisplayValue = false)]
public int ProductId {get;set;}
public string ProductName {get;set;}
[DataType(DataType.MultilineText)]
public string ProductDescription {get;set;}
public decimal ProductPrice {get;set;}
public string ProductCategory { get; set; }
}
}
Here is the ProductViewModel that used throughout the project:
public class ProductsListViewModel
{
public IEnumerable<Product> Products { get; set; }
public PagingInfo _pagingInfo { get; set; }
public PagingInfo PagingInfo { get; set; }
public string CurrentCategory { get; set; }
}
Here is my mapping in the project, I have a automapper to map these two.
public static class AutoMapperConfig
{
public static void RegisterMappings()
{
AutoMapper.Mapper.CreateMap<PRODUCT, Product>();
AutoMapper.Mapper.CreateMap<PRODUCT, Product>()
.ForMember(dest => dest.ProductCategory,
opts => opts.MapFrom(src => src.PRODUCT_CATEGORY));
AutoMapper.Mapper.CreateMap<PRODUCT, Product>()
.ForMember(dest => dest.ProductDescription,
opts => opts.MapFrom(src => src.PRODUCT_DESCRIPTION));
AutoMapper.Mapper.CreateMap<PRODUCT, Product>()
.ForMember(dest => dest.ProductId,
opts => opts.MapFrom(src => src.PRODUCT_ID));
AutoMapper.Mapper.CreateMap<PRODUCT, Product>()
.ForMember(dest => dest.ProductName,
opts => opts.MapFrom(src => src.PRODUCT_NAME));
AutoMapper.Mapper.CreateMap<PRODUCT, Product>()
.ForMember(dest => dest.ProductPrice,
opts => opts.MapFrom(src => src.PRODUCT_PRICE));
}
}
I call RegisterMappings in the Global.asax.cs's Application_Start.
protected void Application_Start()
{
AutoMapperConfig.RegisterMappings();
}
Under these circumstances, I read the contents from Entity framework, their type is PRODUCT, when I try to assign it to Product, I got error. The point that I get error is here:
public ActionResult List(string category,int page = 1)
{
List<PRODUCT> pr = null;
using(ProductContext pb = new ProductContext())
{
ProductsListViewModel model = new ProductsListViewModel
{
//Error is here
Products = pb.ProductsList.Where(p => category == null || p.PRODUCT_CATEGORY == category).OrderBy(i => i.PRODUCT_ID).Skip((page - 1) * PageSize).ToList().Take(PageSize).ToList(),
_pagingInfo = new PagingInfo
{
CurrentPage = page,
ItemsPerPage = PageSize,
TotalItems = category == null ? pb.ProductsList.Count() : pb.ProductsList.Where(e => e.PRODUCT_CATEGORY == category).Count()
},
CurrentCategory = category
};
return View(model);
}
}
The error is this:
Cannot implicitly convert type 'System.Collections.Generic.List' to 'System.Collections.Generic.IEnumerable'. An explicit conversion exists (are you missing a cast?)
How can I overcome this? Thanks in advance.
The error says everything you need to know. In somewhere you are trying to put a List of objects to a IEnumerable of the same objects.
It seems to me that you shoud alter the line
Products = pb.ProductsList.Where(p => category == null || p.PRODUCT_CATEGORY == category)
.OrderBy(i => i.PRODUCT_ID)
.Skip((page - 1) * PageSize)
.ToList().Take(PageSize).ToList()
into
Products = pb.ProductsList.Where(p => category == null || p.PRODUCT_CATEGORY == category)
.OrderBy(i => i.PRODUCT_ID)
.Skip((page - 1) * PageSize)
.Take(PageSize).AsEnumerable()
Related
Can anyone please assist,i have a model that contains a foreign key(ProductCategory).i am trying to call the values of the foreign key but they are not appearing in the view,when i place a breakpoint in the controller all fields appear successful in the raw results view but it seems they are not being passed to the view.
N.B i am using dev express to generate views
public class Product
{
public int Id { get; set; }
public int productCode { get; set; }
public double price { get; set; }
public int ProductCategoryId { get; set; }
public virtual ProductCategory ProductCategory { get; set; }
public Stock itemNo { get; set; }
}
[HttpGet]
public async Task<IActionResult> Get(DataSourceLoadOptions loadOptions) {
var product = _context.Product.Select(i => new {
i.Id,
i.productCode,
i.price,
i.ProductCategoryId,
i.ProductCategory.categoryDescr
});
return Json(await DataSourceLoader.LoadAsync(product, loadOptions));
}
#{
ViewData["Title"] = "Products";
}
<h2 class="content-block">Products</h2>
#(Html.DevExtreme().DataGrid<DevExtremeAspNetCoreApp1.Models.Product>()
.DataSource(ds => ds.Mvc()
.Controller("Products")
.LoadAction("Get")
.InsertAction("Post")
.UpdateAction("Put")
.DeleteAction("Delete")
.Key("Id")
)
.RemoteOperations(true)
.Columns(columns => {
columns.AddFor(m => m.productCode);
columns.AddFor(m => m.price);
columns.AddFor(m => m.ProductCategoryId);
columns.AddFor(m => m.ProductCategory.categoryDescr);
})
.Editing(e => e.Mode(GridEditMode.Popup)
.AllowAdding(true)
.AllowUpdating(true)
.AllowDeleting(true)
.Popup(p=>p
.Title("Product")
.ShowTitle(true)
.Width(500)
.Height(525)
)
)
.Export(e => e.Enabled(true))
)
Try this:
var product = _context.Product.Select(i => new {
i.Id,
i.productCode,
i.price,
i.ProductCategoryId,
ProductCategoryDesc=i.ProductCategory.categoryDescr
});
.....
columns.AddFor(m => m.ProductCategoryDesc);
turns i was passing an anonymous type,correct approach should be:
Controller
public async Task<IActionResult> Get(DataSourceLoadOptions loadOptions) {
var product = _context.Product.Select(i => new {
i.Id,
i.productCode,
i.price,
i.ProductCategoryId,
i.ProductCategory
});
View:
columns.AddFor(m => m.ProductCategory.Id);
I'm trying to include a csv string involvedBody in a View that is generated using AutoMapper but I can't work out where to map the string to the model.
I assumed it would be in the CreateMap call in the controller or as a .ForMember function in the mapping but I can't get it to work. I need to call the InvolvedBodies function and pass the string into the model before the model becomes an IOrderedEnumerable.
Is this possible or do I need to try something else?
ViewModel
public partial class FamilyInterventionListViewModel
{
public int Id { get; set; }
public int interventionId { get; set; }
public string interventionCategory { get; set; }
public string interventionType { get; set; }
public string outcome { get; set; }
public string achievement { get; set; }
public string involvedBody { get; set; }
public string startDate { get; set; }
public string endDate { get; set; }
public string notes { get; set; }
}
Repository
public string InvolvedBodies(int interventionId)
{
var q = (from body in context.tEntity
where body.tIntervention.Any(b => b.interventionID == interventionId)
select body.entityName
);
var ibcsv = string.Join(",", q.ToArray());
return ibcsv;
}
Controller
public ActionResult InterventionType(int Id, string achievement)
{
var model = GetDisplay(Id)
.Where(m => m.achievement == achievement)
.OrderByDescending(m => m.startDate)
;
return PartialView("_interventionType", model);
}
//Automapper for display model
private IEnumerable<FamilyInterventionListViewModel> GetDisplay(int Id)
{
var list = _repo.Get(Id);
Mapper.CreateMap<tIntervention, FamilyInterventionListViewModel>();
IEnumerable<FamilyInterventionListViewModel> viewModel = Mapper.Map <IEnumerable<tIntervention>, IEnumerable<FamilyInterventionListViewModel>>(list);
return viewModel;
}
Mapping
Mapper.CreateMap<tIntervention, FamilyInterventionListViewModel>()
.ForMember(d => d.Id, o => o.MapFrom(s => s.interventionID))
.ForMember(d => d.interventionCategory, o => o.MapFrom(s => s.tOutcome.tInterventionCategory.InterventionCategory))
.ForMember(d => d.interventionType, o => o.MapFrom(s => s.tInterventionType.interventionType))
.ForMember(d => d.outcome, o => o.MapFrom(s => s.tOutcome.outcome))
.ForMember(d => d.achievement, o => o.MapFrom(s => s.tAchievement.achievement))
.ForMember(d => d.involvedBody, o => o.MapFrom(s => s.tEntity.Select(m => m.entityName)))
;
I've not been able to find a solution to this using Automapper so have reverted to manually mapping the csv string after the model is created using:
foreach (var item in model)
{
item.involvedBody = _repo.InvolvedBodies(item.interventionId);
}
I'd be interested to know if this is deemed to be good practice or if there is some other technique I should be using.
I know my problem is really basic. If I write /api/category/1, I wanna list all Tales with the categoryId==1. I wrote this code, but it gives an error.
[HttpGet]
public IEnumerable<Tale> GetAllTalesByCategory(int id)
{
var tales = TaleService.FindAllTale().Select(x => new Tale
{
TaleId = x.TaleId,
TaleName = x.TaleName,
Content = x.Content,
VoicePath = x.VoicePath
}).Where(x => new Tale
{
x.Categories.Select(c => c.CategoryId).First() == id
});
}
Error:
Error 1 Cannot initialize type 'MasalYuvasi.Entities.Tale' with a collection initializer because it does not implement 'System.Collections.IEnumerable' D:\MvcProject\MasalYuvasi\MasalYuvasi\Controllers\DenemeController.cs 33 13 MasalYuvasi
Models:
public class Tale
{
public int TaleId { get; set; }
public string TaleName { get; set; }
public string Content { get; set; }
public string VoicePath { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public Tale()
{
this.Categories = new List<Category>();
}
}
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public virtual ICollection<Tale> Tales { get; set; }
public Category()
{
this.Tales = new List<Tale>();
}
}
Try this:
[HttpGet]
public IEnumerable<Tale> GetAllTalesByCategory(int id)
{
var tales = TaleService.FindAllTale().Select(x => new Tale
{
TaleId = x.TaleId,
TaleName = x.TaleName,
Content = x.Content,
VoicePath = x.VoicePath
}).Where(x => x.Categories.Select(c => c.CategoryId).First() == id).ToList();
}
Fixed the where condition, and added .ToList().
The problem is that your code is using a collection initializer here:
new Tale
{
x.Categories.Select(c => c.CategoryId).First() == id
}
I'm not sure what this code is supposed to be doing, but as x.Categories.Select(c => c.CategoryId).First() == id will return a bool, I don't think this is doing what you want it to.
Based on your comment:
I want to list in the category of tales. Forexample I have 2 tales in CategoryId is 1. If I write "/api/category/1" ı want to list this 2 tales.
I think you are looking for something simpler than what you've got. You want to select Tales (represented by x) where Any of the categories have a CategoryId of id:
.Where(x => x.Categories.Any(c => c.CategoryId == id ));
Note that you can append .ToList() to the end of the where clause, as suggested by pjobs, but this may have a subtle effect on the behavior of your application. For more detail, see LINQ and Deferred Execution.
I want this two methods pass to one view :
public IEnumerable<ProfitAndCostViewModel> getProfitSum()
{
var profBalance = db.Profits
.Where(x => x.IdUser.UserId == WebSecurity.CurrentUserId)
.GroupBy(x => x.IdUser.UserId)
.Select(x => new ProfitAndCostViewModel { ProfitSum = x.Sum(y => y.Value) })
.ToList();
return profBalance;
}
public IEnumerable<ProfitAndCostViewModel> getCostSum()
{
var costBalance = db.Costs
.Where(x => x.IdUser.UserId == WebSecurity.CurrentUserId)
.GroupBy(x => x.IdUser.UserId)
.Select(x => new ProfitAndCostViewModel { CostSum = x.Sum(y => y.Value) })
.ToList();
return costBalance;
}
in my ActionResult I Have this:
ProfitAndCostViewModel pcv = new ProfitAndCostViewModel();
pcv.ProfModel =getProfitSum();
pcv.CostModel =getCostSum();
return View(pcv);
And in ProfitAndCostViewModel code is this:
public double ProfitSum { get; set; }
public double CostSum { get; set; }
public double FinalBalance { get; set; }
public IEnumerable<ProfitAndCostViewModel> ProfModel { get; set; }
public IEnumerable<ProfitAndCostViewModel> CostModel { get; set; }
this is the error:
The model item passed into the dictionary is of type 'WHFM.ViewModels.ProfitAndCostViewModel', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[WHFM.ViewModels.ProfitAndCostViewModel]'.
Create a view model which has them both;
public class BigViewModel
{
public List<ProfitsModel> ProfModel { get; set; }
public List<CostsModel> CostModel { get; set; }
}
And controller
public ActionResult Index()
{
BigViewModel model = new BigViewModel();
model.costBalance = db.Costs...;
model.profBalance = db.Profits...;
return View(model)
}
You can wrap your parameters into a ViewModel or use a ViewBag
My application needs to display a table of customer data, including data about the customer and about his most recent order from a given warehouse. The customer domain object contains a GetLatestOrder(warehouseId) method.
I have a CustomerView viewmodel and want to be able to populate it with some fields from the customer object, and a few fields from the latest order object. Can I do this using Automapper?
Try this,
In Global.asax.cs [Application_Start], public static void AppInitialize()
protected void Application_Start(object sender, EventArgs e)
{
Mapper.CreateMap<Order, CustomerViewModel>()
.ForMember(destination => destination.OrderId, options => options.MapFrom(source => source.Id))
.ForMember(destination => destination.OrderName, options => options.MapFrom(source => source.Name));
Mapper.CreateMap<Customer, CustomerViewModel>()
.ForMember(destination => destination.CustmerId, options => options.MapFrom(source => source.Id))
.ForMember(destination => destination.CustmerName, options => options.MapFrom(source => source.Name))
.ForMember(destination => destination.OrderId, options => options.MapFrom(source => Mapper.Map<IEnumerable<Order>, IEnumerable<CustomerViewModel>>(source.Orders).FirstOrDefault().OrderId))
.ForMember(destination => destination.OrderName, options => options.MapFrom(source => Mapper.Map<IEnumerable<Order>, IEnumerable<CustomerViewModel>>(source.Orders).FirstOrDefault().OrderName));
}
And in your code call the mapper like below,
var lstCustomers = new List<Customer>
{
new Customer { Id = 1, Name="Name", Orders = new List<Order> { new Order { Id = 1000, Name ="Some Name"}}},
};
var result = Mapper.Map<IEnumerable<Customer>, IEnumerable<CustomerViewModel>>(lstCustomers);
I am presumed that you classes looks like below,
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public List<Order> Orders { get; set; }
}
public class Order
{
public int Id { get; set; }
public string Name { get; set; }
}
public class CustomerViewModel
{
public int CustmerId { get; set; }
public string CustmerName { get; set; }
public int OrderId { get; set; }
public string OrderName { get; set; }
}
Also refer this post.
Yes, you can:
var vm = new CustomerViewModel();
Mapper.Map(customer, vm);
Mapper.Map(order, vm);
Each mapping will populate the properties it is configured to and leave the rest.
In the end, I took the easy approach, couldn't find another way:
In Application_start:
Mapper.CreateMap<Customer, CustomerView>();
Mapper.CreateMap<Order, CustomerView>();
In the controller method:
IEnumerable<Customer> customers = GetCustomers(false)
.OrderBy(c => c.Name);
IEnumerable<CustomerView> viewData = Mapper.Map<IEnumerable<Customer>, IEnumerable<CustomerView>>(customers);
foreach (Customer customer in customers)
{
CustomerView view = viewData.Where(cv => cv.CustomerId == customer.CustomerId).First();
Mapper.Map(customer.GetLatestOrder(WarehouseId), view);
}