Automapper entity framework foreign key is null - c#

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!

Related

How to set a foreign key of an object from a one to many relationship in C# ASP.NET in A Controller

I've got two database models, property and units. There is a one to many relationship between property and units i.e 1 x property has many units. This is not a sql question per say, more I guess of and Object Orientated / ASP question.
At the moment, when a user creates a unit, my modelstate is invalid because the propertyId (I think) is null meaning i've got to set the propertyId (Foreign Key) of the Units object / model when the units are created in the units controller. I know this is happening in the create function of the unit controller. Maybe I need to parse in the property object here and then set propertyId of the units however, I can't see / access this.
I'm also keen to get some feedback on the implementation i've chosen for this one to many relationship between property and units in the models.
Property Model
public class Property
{
[Key]
public int Id { get; set; }
[Required]
[Display(Name = "Development Name")]
public string PropertyName { get; set; }
[Required]
[Display(Name = "Development Address")]
public string DevelopmentAddress { get; set; }
[Required]
[Display(Name = "Development Description")]
public string DevelopmentDescription { get; set; }
[Required]
[Display(Name = "Agent Name")]
public string AgentName { get; set; }
[Required]
[Display(Name = "Developer Name")]
public string DeveloperName { get; set; }
[Display(Name = "Image Filename")]
public string ImageFilename { get; set; }
[Display(Name = "Anchor Link")]
public string AnchorLink { get; set; }
//[Display(Name = "Site Plan FileName")]
//public string SitePlanFileName { get; set; }
//[ForeignKey("UserId")]
public string UserId { get; set; }
//public virtual IdentityUser User { get; set; }
public List<Units> Units {get; set; }
}
Units Model
public class Units
{
[Key]
public int UnitId { get; set; }
public string UnitType { get; set; }
public int UnitNumber { get; set; }
public int Price { get; set; }
public int Bedrooms { get; set; }
public int Bathrooms { get; set; }
public int Carspaces { get; set; }
public string Floorplantype { get; set; }
//public int StandardInclusionId{ get; set; }
//public int OptionalInclusionId { get; set; }
public string Floorplanfilenanme { get; set; }
public string Unitanchorlink { get; set; }
public string Internalviewfilename { get; set; }
public string Rentalappraisal { get; set; }
public string Contractfilename { get; set; }
public string Status { get; set; }
public int Id { get; set; }
public Property Property { get; set; }
}
Units Controller:
public async Task<IActionResult> Create([Bind("UnitId,UnitType,UnitNumber,Price,Bedrooms,Bathrooms,Carspaces,Floorplantype,Floorplanfilenanme,Unitanchorlink,Internalviewfilename,Rentalappraisal,Contractfilename,Status,Id")] Units units)
{
if (ModelState.IsValid)
{
_context.Add(units);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
if (!ModelState.IsValid)
{
Console.WriteLine("model not valid" );
}
return View(units);
}
Extract of the database:
I'm honestly stumped on this, I know what needs to happen but I dont know how to do so. I've researched and I think maybe passing in the property object that has the id so that I can set the propertyId (foreignkey) on the units table but there is not getter or setter on the model.
What I need to happen:
Each time a unit is created, it is linked by the foreign key id to the property table.

One to Many and a Many to Many relationship Entity Framework including default Authorization and role managing

I have a system that produce some online classes. In this class we have students and a teacher.
I have used Microsoft default Identity System and Authorization for this system, but something is bothering me in my design.
For more explanation I want to define Roles(Teacher, Students, Admins and etc) , but it is so confusing how to handle relation between Course and Teacher (it is one to many relation) and Course to Students (it has many to many relation).
So I have question is that true way to have two relation between two entities or not? if it is not, How should I handle this?
Here is my Course entity
[Key]
[Display(Name = "شناسه")]
public Guid CourseId { get; set; }
[Required]
[Display(Name = "لوگوی دوره")]
public string LogoPath { get; set; }
[Required]
[Display(Name = "نام دوره")]
public string Name { get; set; }
[Required]
[Display(Name = "شرح دوره")]
public string Description { get; set; }
[Required]
[Display(Name = "شهریه")]
public int Price { get; set; }
[Display(Name = "دارای تخفیف")]
public bool HasDiscount { get; set; }
[Display(Name = "درصد تخفیف")]
public float DiscountPercentage { get; set; }
[Required]
[Display(Name = "آخرین تاریخ به روزرسانی")]
public DateTime LastUpdateUpdate { get; set; }
public string UserId { get; set; }
public AppUser CourseTeacher { get; set; }
public Guid CaptionId { get; set; }
public MainCaption CourseCaption{ get; set; }
public ICollection<Chapter> Chapters { get; set; }
public ICollection<AppUser> Students{ get; set; }
and here is my AppUser entity
[Required]
[Display(Name = "نام")]
public string Firstname { get; set; }
[Required]
[Display(Name = "نام خانوادگی")]
public string LastName { get; set; }
[Required]
[Display(Name = "جنسیت")]
public Gender Gender { get; set; }
[Display(Name = "عنوان")]
public string Title { get; set; }
[Display(Name = "اعتبار")]
public int Credit { get; set; }
[Display(Name = "تاریخ تولد")]
public string BirthDate { get; set; }
[Display(Name = "مدرک تحصیلی")]
public EducationalDegree? Degree { get; set; }
[Display(Name = "آدرس تصویر")]
public string ImagePath { get; set; }
[Display(Name = "تصویر تایید شده")]
public bool? IsImageConfirmed { get; set; }
[Display(Name = "آدرس فیس بوک")]
public string Facebook { get; set; }
[Display(Name = "آدرس اینستاگرام")]
public string Instagram { get; set; }
[Display(Name = "آدرس لینکداین")]
public string Linkedin { get; set; }
[Display(Name = "آدرس توئیتر")]
public string Twitter { get; set; }
[Display(Name = "آدرس وبسایت")]
public string Website { get; set; }
[Display(Name = "تاریخ ثبت نام")]
public DateTime RegisterDate { get; set; }
public ICollection<Course> StudentCourses { get; set; }
public ICollection<Course> TeacherCourses { get; set; }
public ICollection<News> WrittenNews { get; set; }
Tnx to All
Edit
I forgot to say this contains an error Sequence contains more than one matching element and it seems logical
One important this is that if I use same class for inheritance how should I add two relations for this two tables AppUser and Course
I want to define Roles(Teacher, Students, Admins and etc)
You can do it in a couple different ways:
Have User and Role tables and enforce roles on the application level, e.g. Only "teacher" user can do teacher things, only student can enrol into courses etc.
With EF you can use inheritance. Abstract User would have all the common fields and Student, Teacher and Admin would have fields specific only to their role.
Please see the code:
abstract class User
{
public int UserId { get; set; }
public string Name { get; set; }
}
class Teacher : User
{
public string Specialty { get; set; }
}
class Student : User
{
public int Grade { get; set; }
}
See more info here - the example given in this official documentation is very close to what you're trying to achieve.
Course to Students (it has many to many relation)
For this type of a relationship I'd create a new table/entity StudentCourse with composite (StudentId, CourseId) key. And the reason for it is, usually you don't just want a link between 2 entities but also to keep some additional info like Mark, Performance or EnrolmentDate:
class StudentCourse
{
public int StudentId { get; set; }
public int CourseId { get; set; }
public Student Student { get; set; }
public Course Course { get; set; }
// Any additional fields related to the relationship
public int Mark { get; set; }
}

insertion of foreign key asp.net mvc

i have 3 models
public class UsersModel
{
[Key]
public int UserId { get; set; }
[Required]
[StringLength(100, ErrorMessage = "Invalid Name Minimum Length is 5", MinimumLength = 5)]
public string Name { get; set; }
//20150090
public int? student_ID { get; set; }
[Display(Name = "transcript")]
public string transcript { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password do not match.")]
public string ConfirmPassword { get; set; }
[Required]
[StringLength(100, ErrorMessage = "Invalid Name Minimum Length is 2", MinimumLength = 2)]
public string Department { get; set; }
[Required]
[Display(Name = "Phone")]
[DataType(DataType.PhoneNumber,ErrorMessage ="Invalid Phone Number")]
[Range(999999999, 9999999999)]
public int Phone { get; set; }
public int type { get; set; }
}
student
public class StudentsModel
{
[Key]
[Display(Name ="ID")]
public int StudentID { get; set; }
[Required]
public string Name { get; set; }
[Required]//20150090
public string student_ID { get; set; }
[Required]
[Display(Name = "Skills")]
public string Skills { get; set; }
[Required]
[Display(Name = "Gpa")]
[Range(1.00, 4.00, ErrorMessage = "It must be in range 0.00 to 4.00 :)")]
public float Gpa { get; set; }
[Required]
[Display(Name = "Leader")]
public string Leader { get; set; }
[Required]
[Display(Name = "transcript")]
public string transcript { get; set; }
[ForeignKey("UserId")]
public int UserId;
public UsersModel Users { get; set; }
[ForeignKey("IdeaId")]
public int? IdeaId;
public IdeaModel Idea { get; set; }
}
Idea
public class IdeaModel
{
[Required]
[Key]
public int IdeaId { get; set; }
[Required]
public string IdeaName { get; set; }
[Required]
public string IdeaDescription { get; set; }
[Required]
public string tools { get; set; }
public int? SetWith { get; set; }
[Required]
public int Prof1 { get; set; }
public int Prof2 { get; set; }
public int Prof3 { get; set; }
}
when i insert to the database user and student and idea
the foreign key in student model inserted with null value
this is the code for insertion
i want the foreign key in student model to inserted automatically
whit the values of primary key in usernodel and idea model how to make this?
public ActionResult RegisterLeader(regall reg)
{
if (ModelState.IsValid)
{
var user= db.Users.Add(reg.users);
var idea = db.Idea.Add(reg.idea);
var stu = db.Students.Add(reg.students[0]);
db.SaveChanges();
return View("RegisterLeaderPost");
//return Registerfinish();
}
}
this model have the three models
public class regall
{
public List<StudentsModel> students { get; set; }
public UsersModel users { get; set; }
public IdeaModel idea { get; set; }
}
You need to set the Idea property of the student so EF knows to make the relationship.
reg.students[0].Idea = reg.idea;

Ignore property in Automapper from destination to source?

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());

CodeFirst table is not being generated as I would expect

I have a class called Status, and I also have a class called ApplicantPositionHistory which has an OldStatus and a NewStatus.
However the table is being generated like this:
I would expect that the table has a newstatusid and oldstatusid, which should be foreign keys, but it generated those 2 columns duplicated.
public class ApplicationPositionHistory
{
[DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)]
public int ApplicationPositionHistoryID { get; set; }
public ApplicantPosition applicantPosition { get; set; }
[Column("oldStatusID")]
public int oldStatusID { get; set; }
[Column("newStatusID")]
public int newStatusID { get; set; }
public Status oldStatus { get; set; }
public Status newStatus { get; set; }
[StringLength(500, MinimumLength = 3, ErrorMessage = "Comments should not be longer than 500 characters.")]
[Display(Name = "Comments")]
public string comments { get; set; }
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
[Display(Name = "Date")]
public DateTime dateModified { get; set; }
}
public class Status
{
[DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)]
public int StatusID { get; set; }
[StringLength(40, MinimumLength = 3, ErrorMessage = "Status should not be longer than 20 characters.")]
[Display(Name = "Status")]
public string status { get; set; }
}
I think the problem is your non standard naming convention which results in problem when applying default mapping conventions so your FK columns are not paired with navigation properties and EF creates new ones.
Try this to manually pair navigation properties with your FK properties:
[ForeignKey("oldStatusID")]
public Status oldStatus { get; set; }
[ForeignKey("newStatusID")]
public Status newStatus { get; set; }

Categories