Why Web Api include properties in response that are not projected - entity-framework-6

I have a view model
public class MyViewModel
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Position { get; set; }
public string Email { get; set; }
public string Office { get; set; }
public DateTime? StartDate { get; set; }
public int? Age { get; set; }
public int? Salary { get; set; }
public int? Extn { get; set; }
}
And I am doing projection on my entity
public List<ViewModel.StaffViewModel> GetAll()
{
var context = new GistDemoDbEntities();
var model = context.Staff
.Select(s => new ViewModel.StaffViewModel
{
FirstName = s.FirstName,
LastName = s.LastName,
Position = s.Position,
Salary = s.Salary
}).ToList();
return model;
}
And use Web Api to return back as json, but in reponse I found out it includes other properties as well that define in the View Model with vlaue null. I only want to have those properties that I need in reponse, how is it possible?

You can either:
Remove them from your ViewModel, a view model should only conta9in
what you intend to use anyway.
or
Use [JsonIgnore] on your properties to prevent JSON.Net from mapping
them.
Json Ignore is an attribute, look here;
http://james.newtonking.com/json/help/index.html?topic=html/SerializationAttributes.htm

Related

I couldn't figure out the MVC Logic

Entity is:
public partial class Persons
{
public int Id { get; set; }
public string? Name { get; set; }
public string? Surname { get; set; }
public string? Number { get; set; }
public string? Address { get; set; }
public string? PublicId { get; set; }
public string? FatherName { get; set; }
public string? MotherName { get; set; }
}
Also Model is:
public partial class OnlyPrivateProp
{
public int Id { get; set; }
public string? Name { get; set; }
public string? Surname { get; set; }
}
And controller:
public class DemoController : Controller
{
_context c;
public DemoController(_context c)
{
this.c = c;
}
public IActionResult Index()
{
ET model= new ET();
var select = ..............
return View();
}
}
I dont want to use all data to display only three colunms. So I defined a model has three prop. But I cant pass data to model and cant select data and cant send controller.
You could create different ViewModel for different Views
The entities models are mapped to the tables in your database,you could check the documents related with EFCore
For your requirement,you could fill the viewmodel and pass the value to your View as below:
[Table("SomeTable")]
public class SomeEntity
{
public int Id { get; set; }
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public string Prop3 { get; set; }
...........
}
public class ViewModel
{
public string Prop1 { get; set; }
public string Prop3 { get; set; }
}
public IActionResult SomeAction()
{
...........
var vmlist = _context.SomeEntity.Select(x => new ViewModel{ Prop1 = x.Prop1, Prop3 = x.Prop3 }).ToList();
return View(vmlist);
}
And the documents related with MVC

Flatten Domain Class To ViewModel When Source Is Complex

I am using ValueInjecter to map domain classes to my view models. My domain classes are complex. To borrow an example from this question:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Address Address { get; set; }
}
public class Address
{
public int Id { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
}
// VIEW MODEL
public class PersonViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int PersonId { get; set; }
public int AddressId { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
}
I have looked at FlatLoopInjection, but it expects the view model classes to be prefixed with nested domain model type like so:
public class PersonViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Id { get; set; }
public int AddressId { get; set; }
public string AddressCity { get; set; }
public string AddressState { get; set; }
public string AddressZip { get; set; }
}
The OP in the linked question altered his view models to match the convention expected by FlatLoopInjection. I don't want to do that.
How can I map my domain model to the original unprefixed view model? I suspect that I need to override FlatLoopInjection to remove the prefix, but I am not sure where to do this. I have looked at the source for FlatLoopInjection but I am unsure if I need to alter the Match method or the SetValue method.
you don't need flattening, add the map first:
Mapper.AddMap<Person, PersonViewModel>(src =>
{
var res = new PersonViewModel();
res.InjectFrom(src); // maps properties with same name and type
res.InjectFrom(src.Address);
return res;
});
and after that you can call:
var vm = Mapper.Map<PersonViewModel>(person);

Need help trying to create a one-to-many relationship using EF7, Asp.NET and SQLite

I am new to Entity Framework and Asp.NET, and therefore, struggling with creating database relationships within the Entity Framework.
I have two SQLite tables (Ticket and User) and have setup my entity models as follows:
public class Users
{
[ForeignKey("id")]
public int id { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string email { get; set; }
public virtual ICollection<Tickets> Tickets { get; set; }
}
public class Tickets
{
public int id { get; set; }
public string summary { get; set; }
public string description { get; set; }
public string c_location { get; set; }
public string c_store_device { get; set; }
public string category { get; set; }
public DateTime? created_at { get; set; }
public DateTime? closed_at { get; set; }
public int priority { get; set; }
public int? assigned_to { get; set; }
public DateTime? due_at { get; set; }
public DateTime? updated_at { get; set; }
public string status { get; set; }
public virtual Users Users { get; set; }
}
I am trying to use Entity Framework 7 to export an IEnumerable<Tickets> that includes the User assigned to each Ticket.
I have tried to create my model relationship in MyDBContext as a single User can have multiple Tickets, and also has a foreign key associated in my Sqlite database (Tickets.assigned_to = User.id):
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Users - > many Tickets
modelBuilder.Entity<Users>()
.HasMany(p => p.Tickets)
.WithOne(e => e.Users)
.HasForeignKey(p => p.assigned_to);
}
My result ends up with Ticket data being exported, but against every ticket I see a null value for User:
[{"id":10002,...,"Users":null}]
When I use .Include() within my Repository to include each User like this:
public IEnumerable<Tickets> GetAll()
{
return _db.Tickets.Include(t => t.Users).ToList();
}
It results in the error
HTTP Error 502.3 - Bad Gateway
The specified CGI application encountered an error and the server terminated the process.
What I'm trying to retrieve is data that looks like:
{"Ticket";[{"id":10002,..."status":"closed"}],"Users":[{"id":"1"..."email":"johndoe#someplace.com"}]}
I know it probably has something to do with my relationship model, but I cannot work out what I am doing wrong.
First you should really derive your Users from IdentityUser. It helps when trying to wire up the relationship, but I will give you the answer based on your current models. Your ForeignKey property should be on the child entity. By naming conventions, which is what EF uses by default, your public Users Users works better if you put a public int UsersId. Then essentially what EF will do is from your public Users Users it will go to the Users table. Then it looks for the ForeignKey which is set to Id, so now we are in the Users Table looking at the id property. Then it looks for the naming convention UsersId and if it sees it, it will set that property to the value that it saw from the Users Table Id column.
Try using this
public class Users
{
public int id { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string email { get; set; }
public virtual ICollection<Tickets> Tickets { get; set; }
}
public class Tickets
{
public int id { get; set; }
public string summary { get; set; }
public string description { get; set; }
public string c_location { get; set; }
public string c_store_device { get; set; }
public string category { get; set; }
public DateTime? created_at { get; set; }
public DateTime? closed_at { get; set; }
public int priority { get; set; }
public DateTime? due_at { get; set; }
public DateTime? updated_at { get; set; }
public string status { get; set; }
[ForeignKey("Id")]
public int UsersId { get; set; }
public virtual Users Users { get; set; }
}
and for your Fluent API configuring
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Users - > many Tickets
modelBuilder.Entity<Users>()
.HasMany(p => p.Tickets)
.WithOne();
}
Now all that does is create the relationship. In order to view the specific items you want to view, use a ViewModel. So, pull the two lists you want from where you want. Then use logic to separate the list how you want them to display.
public class UsersViewModel()
{
public UsersViewModel(Users user, List<Tickets> tickets)
{
this.first_name = user.first_name;
this.last_name = user.last_name;
this.email = user.email;
this.Tickets = new List<Tickets>();
foreach(var ticket in tickets)
{
if(ticket.UserId == user.Id)
{
this.Tickets.Add(ticket)
}
}
}
public string first_name { get; set; }
public string last_name { get; set; }
public string email { get; set; }
public List<Tickets> Tickets { get; set;}
}
then in your controller make your list
public IActionResult Index()
{
var usersList = _repository.Users.ToList();
var ticketsList = _repository.Tickets.ToList();
var model = new List<UsersViewModel>();
foreach(var user in usersList)
{
var listItem = new UsersViewModel(user, ticketsList);
model.Add(listItem);
}
return View(model);
}
or use a Linq query
public IActionResult Index()
{
var usersList = _repository.Users.ToList();
var model = new List<UsersViewModel>();
foreach(var user in usersList)
{
var ticketsList = from x in _repository.Tickets where x.UserId.Equals(user.Id) select x;
var listItem = new UsersViewModel(user, ticketsList);
model.Add(listItem);
}
return View(model);
}
then at the top of your view you should have
#model IEnumerable<UsersViewModel>

How To Mapping Entity When Editing it in ASP.Net MVC using AutoMapper

i have a view model like this:
public class CityModel
{
public int Id { get; set; }
[Required]
public int ProvinceId { get; set; }
[Required]
public string Caption { get; set; }
public string Description { get; set; }
}
and an entity:
public class City : BaseEntity
{
public int ProvinceId { get; set; }
public string Caption { get; set; }
public string Description { get; set; }
public virtual Province Province { get; set; }
}
and a BaseEntity:
public abstract class BaseEntity
{
public int Id { get; set; }
public DateTime CreatedOn { set; get; }
public string CreatedBy { set; get; }
public DateTime ModifiedOn { set; get; }
public string ModifiedBy { set; get; }
}
i want to map one object of type CityModel to on object of type City In Edit Action using AutoMapper ,
[HttpPost]
public ActionResult Edit(CityModel model)
{
if (ModelState.IsValid)
{
var entity = _cityRepository.GetCity(model.Id);
entity = model.ToEntity();
var operationStatus = _cityRepository.Edit(entity);
if (operationStatus.IsSuccess) operationStatus = _cityRepository.Save();
if (operationStatus.IsSuccess)
RedirectToAction("Index");
}
ViewBag.ProvinceId = new SelectList(_provinceRepository.Provinces, "Id", "Caption", model.ProvinceId);
return View(model);
}
The ToEntity is :
public static City ToEntity(this CityModel model)
{
return Mapper.DynamicMap<CityModel, City>(model);
}
and finally create map from CityModel To City Uses this Code:
Mapper.CreateMap<CityModel, City>()
.ForMember(des => des.Caption, op => op.MapFrom(src => src.Caption.ToPersianContent()))
.ForMember(des => des.Description, op => op.MapFrom(src => src.Description.ToPersianContent()));
when i want to map from CityModel To City , get City From Database. inherited data in city object are correct :
and After Mapping , i want to keep original inherited mapping and automapper ignore mapping this base properties, but null and default values are set to this properties:
I believe you are calling the wrong overload in "ToEntity". You have to pass in the existing entity:
DynamicMap<TSource, TDestination>(TSource source, TDestination destination)

PagedList in MVC3 with IQueryable

I can't understand what i'm doing wrong. Every time I'm getting this error:
The entity or complex type 'BusinessLogic.CompanyWithDivisionCount' cannot be constructed in a LINQ to Entities query.
I need to get info from 'Company' table and divisions count of each company from 'Division' table, and then make PagedList. Here is my 'Company' table:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
using BusinessLogic.Services;
using BusinessLogic.Models.ValidationAttributes;
namespace BusinessLogic.Models
{
public class Company
{
public Company()
{
Country = "US";
Status = true;
}
public int Id { get; set; }
[Required]
[UniqueCompanyName]
public string Name { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public int Zip { get; set; }
public string Country { get; set; }
public string ContactInfo { get; set; }
[Required]
public DateTime EffectiveDate { get; set; }
public DateTime TerminationDate { get; set; }
public bool Status { get; set; }
[Required]
public string URL { get; set; }
public string EAP { get; set; }
public string EAPCredentials { get; set; }
public string BrandingColors { get; set; }
public string Comments { get; set; }
}
}
Here is my domain model:
public class Company
{
public Company()
{
Country = "US";
Status = true;
}
public int Id { get; set; }
[Required]
[UniqueCompanyName]
public string Name { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public int Zip { get; set; }
public string Country { get; set; }
public string ContactInfo { get; set; }
[Required]
public DateTime EffectiveDate { get; set; }
public DateTime TerminationDate { get; set; }
public bool Status { get; set; }
[Required]
public string URL { get; set; }
public string EAP { get; set; }
public string EAPCredentials { get; set; }
public string BrandingColors { get; set; }
public string Comments { get; set; }
}
public class CompanyWithDivisionCount: Company // I'm using this
{
public int DivisionCount { get; set; }
}
Here is my controller:
public ActionResult CompaniesList(int? page)
{
var pageNumber = page ?? 1;
var companies = companyService.GetCompaniesWithDivisionsCount2();
var model = companies.ToPagedList(pageNumber, PageSize);
return View(model);
}
And here is my service part:
public IQueryable<CompanyWithDivisionCount> GetCompaniesWithDivisionsCount2()
{
return (from c in dataContext.Companies.AsQueryable()
select new CompanyWithDivisionCount
{
Id = c.Id,
Name = c.Name,
Status = c.Status,
EffectiveDate = c.EffectiveDate,
URL = c.URL,
EAP = c.EAP,
EAPCredentials = c.EAPCredentials,
Comments = c.Comments,
DivisionCount = (int)dataContext.Divisions.Where(b => b.CompanyName == c.Name).Count()
});
}
}
Thanks for help!!!
Creator of PagedList here. This has nothing to do with PagedList, but rather is an Entity Framework issue (I'm no expert on Entity Framework, so can't help you there). To confirm that this is true, write a unit test along the following lines:
[Test]
public void ShouldNotThrowAnException()
{
//arrange
var companies = companyService.GetCompaniesWithDivisionsCount2();
//act
var result = companies.ToList();
//assert
//if this line is reached, we win! no exception on call to .ToList()
}
I would consider changing you data model if possible so that instead of relating Companies to Divisions by name strings, instead use a properly maintained foreign key relationship between the two objects (Divisions should contain a CompanyID foreign key). This has a number of benefits (including performance and data integrity) and will almost certainly make your life easier moving forward if you need to make further changes to you app (or if any company ever decides that it may re-brand it's name).
If you create a proper foreign key relationship then your domain model could look like
public class Company
{
...
public virtual ICollection<Division> Divisions{ get; set; }
public int DivisionCount
{
get
{
return this.Divisions.Count()
}
}
...
}

Resources