Mapping profile:
Mapper.CreateMap<Customer, CustomerDto>();
Mapper.CreateMap<CustomerDto, Customer>();
Mapper.CreateMap<Movie, MoviesDto>();
Mapper.CreateMap<MoviesDto, Movie>(MemberList.Source);
Movie class:
namespace Demo3.Models
{
public class Movie
{
public int Id { get; set; }
[Required(ErrorMessage = "Please Enter Customer Name")]
[StringLength(255)]
public string Name { get; set; }
public Genre Genre { get; set; }
[Required]
public byte GenreId { get; set; }
public DateTime DateAdded { get; set; }
[Display(Name = "Release Date")]
public DateTime ReleaseDate { get; set; }
[Display(Name = "Number In Stock")]
[Range(1, 20)]
public byte NumberInStock
{
get; set;
}
}
}
MoviesDto class:
namespace Demo3.Dtos
{
public class MoviesDto
{
public int Id { get; set; }
[Required]
[StringLength(255)]
public string Name { get; set; }
[Required]
public byte GenreId { get; set; }
public DateTime ReleaseDate { get; set; }
//public Genre Genre { get; set; }
[Range(1, 20)]
public byte NumberInStock
{
get; set;
}
}
}
Exception:
An exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll but was not handled in user code
and
My need is to ignore the Genre property while saving.
When defining the individual property mappings (which you got away without because they get mapped automagically, by having the same name), you have to specify an ignore instruction, like so:
Mapper.CreateMap<MoviesDto, Movie>()
.ForMember(d => d.Genre, o => o.Ignore());
Related
Currently i have the following structure of my classes:
public class StoreElement
{
[Display(Name="ID")]
public int StoreElementId { get; set; }
[Display(Name = "RegalID")]
public string StoreElementCode { get; set; }
[Display(Name = "Regal")]
public string Storage { get; set; }
[Display(Name="Ebene")]
public string Level { get; set; }
[Display(Name = "Fach")]
public string Shelf { get; set; }
[Display(Name = "ESL Tag")]
public string ESLTagId { get; set; }
[Display(Name ="ESL Layout Template")]
public string ESLLayoutValue { get; set; }
[Display(Name = "Eingelagertes Material")]
public List<Material> Materials { get; set; }
}
And this class:
public class Material
{
[Display(Name = "ID")]
public int MaterialId { get; set; }
[Display(Name = "Materialnummer")]
public int? MaterialNumber { get; set; }
[Display(Name = "Auftragsnummer")]
public int? OrderNumber { get; set; }
[Display(Name = "Eingelagert")]
public bool? IsStored { get; set; }
[Display(Name = "Einlagerdatum")]
public DateTime StoredAt { get; set; }
[Display(Name = "Auslagerdatum")]
public DateTime OutsourcedAt { get; set; }
[Display(Name = "Liefertermin")]
public DateTime DeliveryDate { get; set; }
[Display(Name = "Priorisiertes Material")]
public bool PriorityMaterial { get; set; }
public int? StoreElementId { get; set; }
public StoreElement StoreElement { get; set; }
}
A StoreElement can hold a List of Materials. The class Materials contains a property which is a date. Now i would like to order the Storage-Location List by the subproperty date of a list of materials.
I tried something in linq like that:
var myOrderdStorageLocationsByDeliveryDateOfMaterialsSublist = this.MyDatabaseContext.StorageLocations.Include(x=>x.Materials).OrderBy(x=>x.Materials.OrderBy(y=>y.DeliveryDate)).ToList();
But this throws an exception that says "Failed to compare two elements in the array"
Obviously, you need some value from Materials. And OrderBy won't return it.
I would recommend you to get a particular value for sorting StoreElements based on what logic you need: Min, Max or Average for example.
var myOrderdStorageLocationsByDeliveryDateOfMaterialsSublist = this.MyDatabaseContext.StorageLocations
.Include(x=>x.Materials)
.OrderBy(x=>x.Materials.Min(y=>y.DeliveryDate))
.ToList();
I have a ViewModel with several properties (VM for multi-step wizard):
public class CallViewModel
{
[Key]
[Column(Order = 0)]
[HiddenInput(DisplayValue = false)]
public System.Guid CallID { get; set; }
[Required, Display(Name = "Call Date")]
[DataType(DataType.Date)]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd MM yyyy} г.")]
public System.DateTime CallDate { get; set; }
[Required, Display(Name = "Contract Number")]
public string Number { get; set; }
[Display(Name = "Date of Sampling"), DataType(DataType.Date)]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd MM yyyy} г.")]
public System.DateTime SampleActDate { get; set; }
[Display(Name = "Date of the Contract"), DataType(DataType.Date)]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd MM yyyy} г.")]
public System.DateTime ContractDate { get; set; }
[Required, Display(Name = "Cost Efficiency, %")]
public decimal CostEfficiency { get; set; }
[Required, Display(Name = "Document Type")]
public string CallName { get; set; }
//Representative
[Required, Display(Name = "Second Name")]
public string RepFamilyName { get; set; }
[Required, Display(Name = "First Name")]
public string RepFirstName { get; set; }
[Required, Display(Name = "Middle Name")]
public string RepMidName { get; set; }
[Required, Display(Name = "Position")]
public string RepPosition { get; set; }
[Required, Display(Name = "Document")]
public string DocType { get; set; }
[Required, Display(Name = "Phone (###) ###-##-##")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:(###) ###-##-##}")]
public string RepPhoneNumber { get; set; }
//Customer
[Required, Display(Name = "Judicial Status")]
public string JudicialStatus { get; set; }
[Required, Display(Name = "Customer Name")]
public string CustomerName { get; set; }
[Required, Display(Name = "Address")]
public string CustomerAddress { get; set; }
[Required, Display(Name = "TaxID")]
public string TaxID { get; set; }
[Display(Name = "BIC")]
public string BIC { get; set; }
[Required, Display(Name = "PHone Number (###) ###-##-##")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:(###) ###-##-##}")]
public string CustomerPhoneNumber { get; set; }
[Required, Display(Name = "OKPO")]
public int OKPO { get; set; }
[Required, Display(Name = "Account)]
public string CustomerBankAccount { get; set; }
[Required, Display(Name = "Bank Branch")]
public string BankBranch { get; set; }
[Required, Display(Name = "Bank Address")]
public string BranchAddress { get; set; }
[Display(Name = "Bank Code")]
public Nullable<int> BankCode { get; set; }
[Display(Name = "Cell Phone Number")]
public string MPhoneNumber { get; set; }
//Person
[Required, Display(Name = "Expert")]
//public string Exp { get; set; }
public Guid ExpID { get; set; }
[Required, Display(Name = "Affidavit Number")]
public int AffidavitNum { get; set; }
[Required, Display(Name = "Affidavit Date"),
DataType(DataType.Date)]
public System.DateTime AffidavitDate { get; set; }
public List<ItemClass> ItemsList { get { return _items; } }
private List<ItemClass> _items = new List<ItemClass>();
public class ItemClass
{ //Item
public Guid ItemID { get; set; }
[Required, Display(Name = "Item SubType")]
public Guid ItemSubtype { get; set; }
[Required, Display(Name = "Item Name")]
public string ItemName { get; set; }
[Required, Display(Name = "Producer")]
public string ItemProducer { get; set; }
[Required, Display(Name = "Quantity")]
public int ItemQty { get; set; }
[Display(Name = "Additionals")]
public string Additional { get; set; }
[Required, Display(Name = "Program Name")]
public string ProgramNameShort { get; set; }
[Required, Display(Name = "Calc Date")]
public string calcDate { get; set; }
[Required, Display(Name = "Calc Number")]
public string calcNum { get; set; }
}
}
I also have several entities with 1:n relationships, like
public partial class Call
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Call()
{
this.CallDetails = new HashSet<CallDetail>();
}
public System.Guid CallID { get; set; }
public System.DateTime CallDate { get; set; }
public System.Guid CustomerID { get; set; }
public string DocNumber { get; set; }
public int AffidavitNum { get; set; }
public System.DateTime AffidavitDate { get; set; }
public System.DateTime ContractDate { get; set; }
public int CallStatus { get; set; }
public string DocType { get; set; }
public Nullable<decimal> Cost_Efficiency { get; set; }
public System.DateTime SampleActDate { get; set; }
public string CallName { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<CallDetail> CallDetails { get; set; }
public virtual Customer Customer { get; set; }
}
and
public partial class CallDetail
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public CallDetail()
{
this.Orders = new HashSet<Order>();
}
public System.Guid CallID { get; set; }
public System.Guid ItemID { get; set; }
public int ItemQty { get; set; }
public decimal ItemTestCost { get; set; }
public System.Guid ProgramID { get; set; }
public virtual Call Call { get; set; }
public virtual Item Item { get; set; }
public virtual Program Program { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Order> Orders { get; set; }
}
to name a few.
In [HttpPost] public ActionResult Create (CallViewModel callViewModel) method I should map the ViewModel to those entities. I know that Automapper is among the best ways to perform it, but still I need to understand the principles of correct mapping of VM and related entities (Automapper examples are welcome as well :) ), and especially how to deal with navigation properties (I'm mostly worried about ID properties). Could you please show the best (or template) practice to perform it? Please, be as detailed as possible.
Thanks in advance.
Take this example:
public class ModelClass
{
public Guid Id { get; set; }
public ChildModel ChildModel { get; set; }
}
public class ViewModelClass
{
public Guid Id { get; set; }
public ChildModel ChildModel { get; set; } = new ChildModel();
}
public class ChildModel
{
public Guid Id { get; set; }
}
If you want to map your viewmodel to your model you can do:
[HttpPost]
public ActionResult Create (CallViewModel callViewModel) {
var model = new ModelClass;
model.Id = callViewModel.Id;
model.ChildModel = callViewModel.ChildModel;
_context.Add(model);
_context.SaveChanges();
return RedirectToAction("Index");
}
For the use of automapper I suggest you read the AutoMapper docs :)
I have scenario where I want to know is my model is valid or not.
here is my model
public class CallPartyModel
{
public System.Guid PartyId { get; set; }
public System.Guid FwCallMasterId { get; set; }
[Required(ErrorMessage = "Principal Party is required.")]
[Display(Name = "Principal Party")]
public System.Guid PrincipalPartyId { get; set; }
[Required(ErrorMessage = "Responsible Party is required.")]
[Display(Name = "Responsible Party")]
public System.Guid ResponsiblePartyId { get; set; }
[Display(Name = "File Type")]
public System.Guid FileTypeId { get; set; }
[Display(Name = "Agent Type")]
public Nullable<System.Guid> AgentTypeId { get; set; }
public string AgentTypeCode { get; set; }
public bool AdvancedRequired { get; set; }
public bool SeperateDARequired { get; set; }
public string PrincipalPartyName { get; set; }
public string ResponsiblePartyName { get; set; }
public string PrincipalReferenceCode { get; set; }
public string ResponsibleReferenceCode { get; set; }
public string FileTypeName { get; set; }
public string FileTypeCode { get; set; }
public string AgentTypeName { get; set; }
public bool? DAIssuedFlag { get; set; }
[Range(0, 999999999.999, ErrorMessage = "Value lies outside the 0 to 999999999.999 range")]
public decimal? AdvanceReceivedAmount { get; set; }
public System.Guid CreatedBy { get; set; }
public System.DateTime CreatedDateTime { get; set; }
public Nullable<System.Guid> ModifiedBy { get; set; }
public Nullable<System.DateTime> ModifiedDateTime { get; set; }
public bool IsDeleted { get; set; }
public Nullable<System.Guid> DeletedBy { get; set; }
public Nullable<System.DateTime> DeletedDateTime { get; set; }
//public virtual UserModel FwCore_Users { get; set; } //Created By User
//public virtual UserModel FwCore_Users1 { get; set; }//Modified By User
//public virtual UserModel FwCore_Users2 { get; set; }// Deleted by User
public bool IsDirtyCheck { get; set; }
public bool LockPrinFlag { get; set; }
public string LockPrinMsg { get; set; }
}
I have defined some rules for this ex. public decimal? AdvanceReceivedAmount { get; set; }
the range rule.
I know how to check model state when our model is bonded to view as ModelState.Isvalid()
but in my code I am working with tow diffident models, its in some wcf service, where I am getting the input as string for all properties and I can't define the data annotation rule on second model. So I have to transfer the data manually from model one to model two and in model two (CallPartyModel) I have define the data annotation rules. Now before performing any transaction in database, I have to check if the model properties's value are valid or not, I know I can do it manually but is there any method as modelState.IsValid() for this kind of scenario?
as:
CallPartyModel obj=new CallPartyModel();
obj.AdvanceReceivedAmount=88.88;
if(obj.IsValid())
{
//go
}
else
{
//Show the error according to property
}
Any suggestion or help will be appreciated
How about you check your model1 against model2 by loading the model2 with the values of Model1 and then using
Model2 m2 = new Model2();
//... load up the values into m2 from Model1
if(TryUpdateModel(m2)) //if it is ok (checks validation)
{
... your code...
}
I hope this helps.
When running a LINQ query, it runs fine and gets the expected results when I include the "result.Dump()" method. The anonymous types work fine.
However, I need to put this anonymous type inside my model and am having the following conversion problem (see image - view image with your favorite viewer).
Customer is a parent of Projects with the below models. I cannot use typed models due to the following exception in the code:
The entity or complex type 'CodeFirstNamespace.Customer' cannot be constructed in a LINQ to Entities query.
namespace YeagerTechDB.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
[Serializable, DataContract(IsReference = true)]
public partial class Customer
{
public Customer()
{
Projects = new HashSet<Project>();
}
[Key]
[ScaffoldColumn(true)]
[Display(Name = "ID")]
[DataMember]
public short CustomerID { get; set; }
[Required]
[StringLength(256)]
[DataMember]
public string UserName { get; set; }
[Required]
[StringLength(50)]
[EmailAddress]
[DataMember]
public string Email { get; set; }
[StringLength(50)]
[DataMember]
public string Company { get; set; }
[StringLength(50)]
[DataMember]
public string FirstName { get; set; }
[StringLength(50)]
[DataMember]
public string LastName { get; set; }
[StringLength(50)]
[DataMember]
public string Address1 { get; set; }
[StringLength(50)]
[DataMember]
public string Address2 { get; set; }
[StringLength(50)]
[DataMember]
public string City { get; set; }
[StringLength(2)]
[DataMember]
public string State { get; set; }
[StringLength(10)]
[DataType(DataType.PostalCode)]
[RegularExpression(#"^\d{5}(-\d{4})?$", ErrorMessage = "Must match 99999 or 99999-9999 format")]
[DataMember]
public string Zip { get; set; }
[StringLength(12)]
[DataType(DataType.PhoneNumber)]
[RegularExpression(#"^\s*([\(]?)\[?\s*\d{3}\s*\]?[\)]?\s*[\-]?[\.]?\s*\d{3}\s*[\-]?[\.]?\s*\d{4}$", ErrorMessage = "Must match 999-999-9999 format")]
[DataMember]
public string HomePhone { get; set; }
[StringLength(12)]
[DataType(DataType.PhoneNumber)]
[RegularExpression(#"^\s*([\(]?)\[?\s*\d{3}\s*\]?[\)]?\s*[\-]?[\.]?\s*\d{3}\s*[\-]?[\.]?\s*\d{4}$", ErrorMessage = "Must match 999-999-9999 format")]
[DataMember]
public string CellPhone { get; set; }
[StringLength(100)]
[DataType(DataType.Url)]
[DataMember]
public string Website { get; set; }
[StringLength(50)]
[DataType(DataType.Url)]
[DataMember]
public string IMAddress { get; set; }
[DataType(DataType.DateTime)]
[Display(Name = "Created")]
[DataMember]
public DateTime CreatedDate { get; set; }
[Display(Name = "Updated")]
[DataType(DataType.DateTime)]
[DataMember]
public DateTime? UpdatedDate { get; set; }
[DataMember]
public virtual ICollection<Project> Projects { get; set; }
}
}
namespace YeagerTechDB.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
[Serializable, DataContract(IsReference = true)]
public partial class Project
{
[Key]
[ScaffoldColumn(false)]
[Editable(false)]
[Display(Name = "Proj ID")]
[DataMember]
public short ProjectID { get; set; }
[ScaffoldColumn(false)]
[Editable(true)]
[Display(Name = "Cust ID")]
[DataMember]
public short CustomerID { get; set; }
[Required(ErrorMessage = "Required!")]
[StringLength(30)]
[Display(Name = "Project Name")]
[DataMember]
public string Name { get; set; }
[Required]
[DataType(DataType.MultilineText)]
[DataMember]
public string Description { get; set; }
[ScaffoldColumn(true)]
[Display(Name = "Category")]
[DataMember]
public short CategoryID { get; set; }
[ScaffoldColumn(true)]
[Display(Name = "Priority")]
[DataMember]
public short PriorityID { get; set; }
[ScaffoldColumn(true)]
[Display(Name = "Status")]
[DataMember]
public short StatusID { get; set; }
[DataType(DataType.Currency)]
[DataMember]
public decimal? Quote { get; set; }
[DataType(DataType.MultilineText)]
[DataMember]
public string Notes { get; set; }
[DataType(DataType.DateTime)]
[Display(Name = "Created")]
[DataMember]
public DateTime CreatedDate { get; set; }
[DataType(DataType.DateTime)]
[Display(Name = "Updated")]
[DataMember]
public DateTime? UpdatedDate { get; set; }
[DataMember]
public virtual Category Category { get; set; }
[DataMember]
public virtual Customer Customer { get; set; }
[DataMember]
public virtual Priority Priority { get; set; }
[DataMember]
public virtual Status Status { get; set; }
[DataMember]
public virtual ICollection<TimeTracking> TimeTrackings { get; set; }
}
}
I am trying to update the database using entity framework, I map my entities to viewmodels using automapper, and map it back the same way:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([FromJson] MyCVViewModel model)
{
var userId = User.Identity.GetUserId();
//find the cv
CV cv = repository.FindCV(model.CVId);
//auto mapper mapping
Mapper.CreateMap<MyCVViewModel, CV>();
Mapper.CreateMap<MyCompanyViewModel, Company>();
cv = Mapper.Map<MyCVViewModel, CV>(model, cv);
//edit
repository.EditCV(cv);
}
When I map it back, the foreign key CVid inside company entity becomes 0, i think something was lost during the mapping process, how do you map the foreign key?
Here is my view model and entity:
View Model:
public class MyCVViewModel
{
public int CVId { get; set; }
[Required]
[StringLength(100, ErrorMessage = "Title cannot exceed 100 characters.")]
[Display(Name = "Title")]
public string Title { get; set; }
[Required]
[StringLength(1000, ErrorMessage = "Statment cannot exceed 1000 characters.")]
[Display(Name = "Statement")]
public string Statement { get; set; }
public bool Reference { get; set; }
public List<MyCompanyViewModel> Companies { get; set; }
}
public class MyCompanyViewModel
{
[Required]
[StringLength(100, ErrorMessage = "Company Name cannot exceed 100 characters.")]
[Display(Name = "Company Name")]
public string CompanyName { get; set; }
[Required]
[StringLength(100, ErrorMessage = "Job Title cannot exceed 100 characters.")]
[Display(Name = "Job Title")]
public string JobTitle { get; set; }
[Required]
[DataType(DataType.Date)]
[Display(Name = "Start Date")]
public DateTime StartDate { get; set; }
[Required]
[DataType(DataType.Date)]
[Display(Name = "End Date")]
public DateTime EndDate { get; set; }
[Required]
[StringLength(1000, ErrorMessage = "Job Description cannot exceed 1000 characters.")]
[Display(Name = "Job Description")]
public string Description { get; set; }
}
Entity:
public class CV
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CVId { get; set; }
public string Title { get; set; }
public string Statement { get; set; }
public bool Reference { get; set; }
public virtual ICollection<Company> Companies { get; set; }
}
public class Company
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CompanyId { get; set; }
public string CompanyName { get; set; }
public string JobTitle { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public string Description { get; set; }
public virtual CV CV { get; set; }
public int CVId { get; set; }
}
and this is the error message when I try to update:
The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value.
I see where the problem is, but don't know how to tell automapper to retain foreign key value
MyCompanyViewModel class does not contain a definition of CVId property, so by default Automapper does not know where he should take a value for injecting into Company's CVId property. Just define it:
public class MyCompanyViewModel
{
public int CVId { get; set; }
// Other properties
}
Then for each CompanyViewModel add corresponding hidden input field into the view:
#for (int i = 0; i < Model.Companies.Count; i++)
{
// ...
#Html.HiddenFor(m => Model.Companies[i].CVId)
// ...
}
and you are good to go!