CodeFirst table is not being generated as I would expect - c#

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; }

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; }
}

The specified type member is not supported in LINQ to Entities. - Linq .Contains

I am performing a search on my table however the Linq field I am searching on is not found in the database table but one that I created in the Model. In the table I am searching I record a Created_By field that is actually a user ID. I display the user's full name that I build from another table. I would like the user to be able to search on CreatedFullName. In my table that they are searching the result set shows CreatedFullName that I defined in its Model however it will not allow me to search it because it is not in the actual table. I receive the following error
{"The specified type member 'CreateFullName' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported."}
My Model defines the field as -
public string CreateFullName { get; set; }
I add the field to the result set by
foreach (DeviceLog x in devicelogs)
{
//Retreive full name for Created By and Modified By
x.CreateFullName = GetFullName(x.CREATED_BY);
if (x.MODIFIED_BY != null)
{
x.ModifiedFullName = GetFullName(x.MODIFIED_BY);
}
}
My Linq query .Where statement
if (!String.IsNullOrEmpty(searchString3))
{
devicelogs = devicelogs.Where(s => s.CreateFullName.Contains(searchString3));
ViewBag.Search = "Search";
}
My entire Model
public int DeviceLogID { get; set; }
public int DeviceLogTypeID { get; set; }
public int DeviceID { get; set; }
[Required]
[DataType(DataType.MultilineText)]
[Display(Name = "Device Log Entry")]
public string DeviceLogEntry { get; set; }
[Required]
[Display(Name = "Entry Date")]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public System.DateTime EntryDate { get; set; }
[Display(Name = "Date Created")]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public System.DateTime DATE_CREATED { get; set; }
[Display(Name = "Created By")]
public string CREATED_BY { get; set; }
[Display(Name = "Date Modified")]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime? DATE_MODIFIED { get; set; }
[Display(Name = "Modified By")]
public string MODIFIED_BY { get; set; }
[Display(Name = "Entry Number")]
public int EntryNumber { get; set; }
public bool Corrected { get; set; }
public virtual Device Device { get; set; }
public virtual DeviceLogType DeviceLogType { get; set; }
public virtual ICollection<DeviceLogAudit> DeviceLogAudits { get; set; }
public string CreateFullName { get; set; }
public string ModifiedFullName { get; set; }
What is devicelogs? iqueryable? Try to use .ToList(); when you first assign data to devicelogs.
EF can't convert your query to SQL, because CreateFullName doesn't exist in the database.
Assume you've created foreign keys for CREATED_BY and MODIFIED_BY to the Users table, then EF shouldhave created pseudo-fields with names like `CREATED_BYUser". Use those in you query:
devicelogs = devicelogs.Where(s => s.CREATED_BYUser.FullName.Contains(searchString3));

Automapper entity framework foreign key is null

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!

ViewModel for every View

In my project i have one viewmodel per domainmodel and reuse this viewmodel in more then one view.
Example of one viewmodel
public class ProductViewModel
{
public int ProductId { get; set; }
public int ProductGroupId { get; set; }
public bool IsLinkedToErp { get; set; }
[Required(AllowEmptyStrings = false)]
[Display(Name = "Standard")]
public bool IsDefault { get; set; }
[MaxLength(50)]
[Required(AllowEmptyStrings = false)]
[Display(Name = "Artnr")]
public string ArtNo { get; set; }
[MaxLength(255)]
[Required(AllowEmptyStrings = false)]
[Display(Name = "Beskrivning")]
public string Description { get; set; }
[MaxLength(255)]
[Required(AllowEmptyStrings = false)]
[Display(Name = "Specifikation")]
public string Specification { get; set; }
[MaxLength(5)]
[Required(AllowEmptyStrings = false)]
[Display(Name = "Enhet")]
public string Unit { get; set; }
[MaxLength(4)]
[Required(AllowEmptyStrings = false)]
[Display(Name = "Konto")]
public string Account { get; set; }
[Required(AllowEmptyStrings = false)]
[Display(Name = "Netto")]
public decimal NetPrice { get; set; }
public string ChUser { get; set; }
public DateTime ChTime { get; set; }
public string GetUpdatedDate
{
get { return String.Format("{0:d}", ChTime); }
}
public string GetNetPrice
{
get { return String.Format("{0:0.00}", NetPrice); }
}
}
All my views in ProductController reuse this ViewModel.
For List, Add and Edit. But in list i only use a few of all properties.
Then i using Automapper to map to Domain and vice versa.
Now I'm wondering if anyone has experience of this. Do you think I will have problems using this solution as the project grows?
I would consider splitting out the ListViewModel and the Add/Edit view models if only because you are potentially populating and sending more data than you really need to your view.
By leveraging from inheritance, you could quickly make two classes that contain only the data that you need for your view. Based on your example, I would consider the following:
public class ProductListViewModel{
public IEnumerable<ProductListModel> products {get;set;}
public string SomeOtherPotentialVariableForProductList {get;set;}
}
public class ProductListModel{
public int ProductId { get; set; }
public int ProductGroupId { get; set; }
[MaxLength(255)]
[Required(AllowEmptyStrings = false)]
[Display(Name = "Beskrivning")]
public string Description { get; set; }
[Required(AllowEmptyStrings = false)]
[Display(Name = "Netto")]
public decimal NetPrice { get; set; }
}
public class ProductViewModel : ProductListModel
{
public bool IsLinkedToErp { get; set; }
[Required(AllowEmptyStrings = false)]
[Display(Name = "Standard")]
public bool IsDefault { get; set; }
[MaxLength(50)]
[Required(AllowEmptyStrings = false)]
[Display(Name = "Artnr")]
public string ArtNo { get; set; }
[MaxLength(255)]
[Required(AllowEmptyStrings = false)]
[Display(Name = "Specifikation")]
public string Specification { get; set; }
[MaxLength(5)]
[Required(AllowEmptyStrings = false)]
[Display(Name = "Enhet")]
public string Unit { get; set; }
[MaxLength(4)]
[Required(AllowEmptyStrings = false)]
[Display(Name = "Konto")]
public string Account { get; set; }
public string ChUser { get; set; }
public DateTime ChTime { get; set; }
public string GetUpdatedDate
{
get { return String.Format("{0:d}", ChTime); }
}
This accomplishes a few things.
You are only sending the data that is required for the view.
If you find yourself needing more information for the list view that may not be directly related to a product, you can quickly add that property.
By inheriting from the ProductListModel, you are not repeating yourself within your code.

Categories