MVC Entity Framework Models and Relationships - asp.net-mvc

im quite new to ASP.net and entity framework. I created a class but im just going to simplify it and take the example class from Microsoft. So here we go. These are all the example classes
public class Student
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime EnrollmentDate { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
public class Instructor
{
public int ID { get; set; }
[Required]
[Display(Name = "Last Name")]
[StringLength(50)]
public string LastName { get; set; }
[Required]
[Column("FirstName")]
[Display(Name = "First Name")]
[StringLength(50)]
public string FirstMidName { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[Display(Name = "Hire Date")]
public DateTime HireDate { get; set; }
[Display(Name = "Full Name")]
public string FullName
{
get { return LastName + ", " + FirstMidName; }
}
public virtual ICollection<Course> Courses { get; set; }
public virtual OfficeAssignment OfficeAssignment { get; set; }
}
public class OfficeAssignment
{
[Key]
[ForeignKey("Instructor")]
public int InstructorID { get; set; }
[StringLength(50)]
[Display(Name = "Office Location")]
public string Location { get; set; }
public virtual Instructor Instructor { get; set; }
}
public class Course
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Display(Name = "Number")]
public int CourseID { get; set; }
[StringLength(50, MinimumLength = 3)]
public string Title { get; set; }
[Range(0, 5)]
public int Credits { get; set; }
public int DepartmentID { get; set; }
public virtual Department Department { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
public virtual ICollection<Instructor> Instructors { get; set; }
}
Like i said this is just for a example im trying to get know it.
My First Question: Do you need something like DepartmentID When you already do public virtual Department Department?
Second question: When i have a Collection of data how do i add values or Ids to that collection in the controller i can find this anywhere.
Third Question: Can some one link me a complete MVC example application with proper relationships

Related

Query and display in one view data coming from many to many with payload in Entity framework 6

I have this complex model:
public class Food
{
[Key]
public int FoodID { get; set; }
[Required]
[DisplayName("Food Name")]
public string FoodNameEN { get; set; }
[Required]
[DisplayName("Food Name")]
public string FoodNameFR { get; set; }
[Required]
[DisplayName("Food Name")]
public string FoodNameNL { get; set; }
[Required]
[DisplayName("Food Description")]
public string FoodDescriptionEN { get; set; }
[Required]
[DisplayName("Food Description")]
public string FoodDescriptionFR { get; set; }
[Required]
[DisplayName("Food Description")]
public string FoodDescriptionNL { get; set; }
public int CategoryID { get; set; }
[Required]
public bool Availability { get; set; }
[Required]
[DisplayName("Is Menu of the Day")]
public bool DailyMenu { get; set; }
public virtual Category Category { get; set; }
public virtual ICollection<FoodAttributeValue> FoodAttributeValues { get; set; } = new HashSet<FoodAttributeValue>();
public virtual ICollection<OrderDetail> OrderDetails { get; set; } = new HashSet<OrderDetail>();
public class Category
{
[Key]
public int CategoryID { get; set; }
[Required(ErrorMessage = "Please enter a Category Name for English")]
[DisplayName("Category Name")]
public string CategoryEN { get; set; }
[Required(ErrorMessage = "Please enter a Category Name for French")]
[DisplayName("Category Name")]
public string CategoryFR { get; set; }
[Required(ErrorMessage = "Please enter a Category Name for Dutch")]
[DisplayName("Category Name")]
public string CategoryNL { get; set; }
[Required]
public bool Availability { get; set; }
public virtual ICollection<Food> Foods { get; set; } = new HashSet<Food>();
}
public class Attribute
{
[Key]
public int AttributeID { get; set; }
public string AttributeNameEN { get; set; }
public string AttributeNameFR { get; set; }
public string AttributeNameNL { get; set; }
public virtual ICollection<AttributeValue> AttributeValues { get; set; } = new HashSet<AttributeValue>();
}
public class AttributeValue
{
[Key]
public int AttributeValueID { get; set; }
public int AttributeID { get; set; }
public string AttributeValueEN { get; set; }
public string AttributeValueFR { get; set; }
public string AttributeValueNL { get; set; }
public virtual Attribute Attribute { get; set; }
public virtual ICollection<FoodAttributeValue> FoodAttributeValues { get; set; } = new HashSet<FoodAttributeValue>();
}
public class FoodAttributeValue
{
[Key]
[Column(Order = 0), ForeignKey("Food")]
public int FoodID { get; set; }
[Key]
[Column(Order = 1), ForeignKey("AttributeValue")]
public int AttributeValueID { get; set; }
public decimal Price { get; set; }
public string CreatorUserName { get; set; }
public DateTime DateCreated { get; set; }
public virtual Food Food { get; set; }
public virtual AttributeValue AttributeValue { get; set; }
}
Attributes contains an attribute type like size or volume
AttributeValue contains the values for an attribute, like Normal Size, or Large.
FoodAttributeValue is a many to many table with payload "Price". So basically, the same Food comes in different sizes with different Prices.
My DatabaseContext:
public class ModelContext: DbContext
{
public DbSet<Category> Categories { get; set; }
public DbSet<Food> Foods { get; set; }
public DbSet<Attribute> Attributes { get; set; }
public DbSet<AttributeValue> AttributesValues { get; set; }
public DbSet<FoodAttributeValue> FoodAttributeValues { get; set; }
}
How can i query the model using linq, with the intention to have on the same view, the list of Foods that contain also the Attributes of the Food, the AttributeValues of it and eventually the Price?
Thanks in advance!
In MVC it is a best practice to create a ViewModel (or DTO) designed for the view you want to display. Generally, try to avoid using your entity POCOs in the view.
So for example:
public class FoodIndexViewModel
{
// Add the various entity fields you want here.
public int FoodID { get; set; }
...
// Take all these annotations out of your entity model. They belong here.
[Required]
[DisplayName("Food Name")]
public string FoodNameEN { get; set; }
...
[Required(ErrorMessage = "Please enter a Category Name for English")]
[DisplayName("Category Name")]
public string CategoryEN { get; set; }
public decimal Price { get; set; }
... etc. etc.
}
Now you can compose a LINQ query to populate the view model. AutoMapper can greatly ease this process.
var listOfFoodsVM = context.Foods
.Where(food => food.Availability)
.Select(food => new FoodIndexViewModel
{
FoodId = food.FoodId,
FoodNameEN = food.FoodNameEN,
... // other fields from food
CategoryEN = food.Category.CategoryEN,
// Here you would either pick a single value from the list based on your criteria
Price = food.FoodAttributeValues.FirstOrDefault(fav => fav.AttributeValueID == 1).Price
// or you could include a collection of FoodAttributes in your viewmodel:
FoodAtributes = food.FoodAttributes
... etc.
}).ToList();
Now you pass this into your view.
return View(listOfFoodsVM );

Advice on datamodel structure

I'm practicing with ASP.Net MVC 5, and I'm attempting to build a prototype events directory. I've started with a basic layout, adapted from the Contoso University tutorial, but I want to start to develop a more complex data model, however I'm unsure as to the best way to develop the model, specifically, the different pricing options each listing can have.
My current data model is;
Vendors
public class Vendor
{
public int ID { get; set; }
[Required]
[Display(Name = "Company Name")]
[StringLength(50, ErrorMessage = "Company name cannot be longer than 50 characters.")]
public string CompanyName { get; set; }
[Required]
[Display(Name = "First Name")]
[StringLength(50, ErrorMessage = "First name cannot be longer than 50 characters.")]
public string ContactFirstName { get; set; }
[Required]
[Display(Name = "Last Name")]
[StringLength(50, ErrorMessage = "Last name cannot be longer than 50 characters.")]
public string ContactLastName { get; set; }
[Required]
[Display(Name = "Address")]
public string Address { get; set; }
[Required]
[Display(Name = "Address Line 2")]
public string AddressLine2 { get; set; }
[Required]
public string Region { get; set; }
[Required]
public string City { get; set; }
[Required]
public string Postcode { get; set; }
[Required]
[Display(Name = "Email Address")]
public string Email { get; set; }
[Required]
[Display(Name = "Phone Number")]
public string Phone { get; set; }
[Display(Name = "Twitter #username")]
public string TwitterHandle { get; set; }
[Display(Name = "Facebook URL")]
public string FacebookURL { get; set; }
[Required]
[Display(Name = "Active Vendor?")]
public Boolean ActiveStatus { get; set; }
public virtual ICollection<Listing> Listings { get; set; }
}
Listings
public class Listing
{
public int ListingID { get; set; }
public int CategoryID { get; set; }
public int VendorID { get; set; }
[Required]
[Display(Name = "Listing Name")]
public string ListingName { get; set; }
[Required]
[Display(Name = "Listing Description")]
public string ListingDesc { get; set; }
[Required]
[Display(Name = "Maximum Capacity")]
public int Capacity { get; set; }
[Required]
[DataType(DataType.Currency)]
[Display(Name = "Price Per Guest")]
public decimal PricePerGuest { get; set; }
[Required]
public string Address { get; set; }
[Display(Name = "Address Line 2")]
public string Address2 { get; set; }
[Required]
public string City { get; set; }
[Required]
public string Postcode { get; set; }
public virtual Category Category { get; set; }
public virtual Vendor Vendor { get; set; }
}
Categories
public class Category
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public string CategoryDescription { get; set; }
public virtual ICollection<Listing> Listings { get; set; }
}
Ideally, I'd like to add to the Listing table a new property called 'Fixed Price', giving vendors the option to either list by price per guest or by fixed price, as not all vendors can price their services by price per guest.
Is a separate table with pricing options sufficient enough to develop this further?
P.S - I haven't yet started to format the entities properly yet, hence why categories is missing validation and so on.
Price (currency) and IsFixedPrice (bit) Instead of PricePerGuest
Thanks to #Nikhil Vartak for the answer

Validate a field in a model against a field in a referenced model

I have a model that references another model and I'd like to validate using data from the referenced model. Is this possible?
Here's my model:
namespace PHAMVC.Models {
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using ExpressiveAnnotations.Attributes;
[Table("Address")]
public partial class Address {
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int AddressID { get; set; }
public int PHAMemberID { get; set; }
[Display(Name = "Address Type (Home/Mailing/Other)")]
public int AddressTypeID { get; set; }
[Required]
[StringLength(60)]
[Display(Name = "Street")]
public string AddressLine1 { get; set; }
[StringLength(60)]
[Display(Name = " ")]
public string AddressLine2 { get; set; }
public int ZipCodeID { get; set; }
[AssertThat("(AddressTypeID == 1 && DistrictID != 0) || (AddressTypeID != 1)", ErrorMessage = "School District MUST be identified for your Home Address.")]
[Display(Name = "School District Name")]
public int DistrictID { get; set; }
public virtual AddressType AddressType { get; set; }
public virtual District District { get; set; }
public virtual ZipCode ZipCode { get; set; }
}
}
And here is the District model:
namespace PHAMVC.Models {
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
[Table("District")]
public partial class District {
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public District() {
Addresses = new HashSet<Address>();
}
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Display(Name = "School District Name")]
public int DistrictID { get; set; }
[Required]
[StringLength(50)]
[Display(Name = "School District Name")]
public string DistrictName { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
[StringLength(4)]
public string DistrictCode { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public int? CountyNumber { get; set; }
public long? NCESDistrictID { get; set; }
[Required]
[StringLength(50)]
public string CountyName { get; set; }
[Required]
[StringLength(60)]
public string StreetAddress { get; set; }
[Required]
[StringLength(50)]
public string City { get; set; }
[Required]
[StringLength(2)]
public string StateCode { get; set; }
[StringLength(15)]
public string Phone { get; set; }
[StringLength(2)]
public string LocaleCode { get; set; }
[StringLength(25)]
public string Locale { get; set; }
public double? StudentTeacherRatio { get; set; }
public int? Students { get; set; }
public int? Teachers { get; set; }
public int? Schools { get; set; }
public int ZIP { get; set; }
public int? ZIPPlus4 { get; set; }
[StringLength(25)]
public string DistrictType { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public bool? isRegularDistrict { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public bool? isRegionalDistrict { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public bool? isStateDistrict { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public bool? isSCCounty { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
[StringLength(100)]
public string DisplayName { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Address> Addresses { get; set; }
}
}
What I'm trying to do in the Address Model, conceptually is this:
[AssertThat("ZipCodeID == District.ZIP")]
public int DistrictID { get; set; }
It seems reasonable since the District model is referenced in the Address model, but it produces this exception:
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: ExpressiveAnnotations.Analysis.ParseErrorException: Parse error on line 1, column 22:
... ZIP ...
^--- Only public properties, constants and enums are accepted. Identifier 'ZIP' not known.
Am I missing some obvious way to make District.Zip PUBLIC in the Address model?
I'm really new to this, so any guidance or help would be greatly appreciated!

EF Code First not generating join tables for n:m relationships

I've been using this tutorial as a guide for code first n:m. I usually go with db first but for a school project I have to use code first...
My 2 classes are as follows:
public class Product
{
public Product()
{
Stocks = new HashSet<Stock>();
ServingUnits = new HashSet<Unit>();
Orders = new HashSet<Order>();
}
public int ProductId { get; set; }
[StringLength(128, MinimumLength = 1)]
[Required]
public string Title { get; set; }
[StringLength(512, MinimumLength = 1)]
public string Description { get; set; }
public int ExperationPeriod { get; set; }
public byte[] Image { get; set; }
[Required]
public DateTime DateCreated { get; set; }
//foreign keys
[Required]
public int StockUnitId { get; set; }
[Required]
public string CreatedById { get; set; }
[Required]
public int ProductStateId { get; set; }
[Required]
public int ProductTypeId { get; set; }
//navigation properties
[ForeignKey("StockUnitId")]
public virtual Unit StockUnit { get; set; }
[ForeignKey("CreatedById")]
public virtual ApplicationUser CreatedBy { get; set; }
[ForeignKey("ProductStateId")]
public virtual ProductState ProductState { get; set; }
[ForeignKey("ProductTypeId")]
public virtual ProductType ProductType { get; set; }
public virtual ICollection<Stock> Stocks { get; set; }
public virtual ICollection<Unit> ServingUnits { get; set; }
public virtual ICollection<Order> Orders { get; set; }
}
and the other:
public class Unit
{
public Unit()
{
Orders = new HashSet<Order>();
ProductsStock = new HashSet<Product>();
ProductsServe = new HashSet<Product>();
}
public int UnitId { get; set; }
[StringLength(255, MinimumLength = 1)]
[Required]
public string Title { get; set; }
[StringLength(128, MinimumLength = 1)]
public string ShortName { get; set; }
public string Description { get; set; }
[Required]
public double BasisFactor { get; set; }
[Required]
public DateTime DateCreated { get; set; }
//foreign keys
[Required]
public string CreatedById { get; set; }
//navigation properties
[ForeignKey("CreatedById")]
public virtual ApplicationUser CreatedBy { get; set; }
public virtual ICollection<Product> ProductsStock { get; set; }
public virtual ICollection<Product> ProductsServe { get; set; }
public virtual ICollection<Order> Orders { get; set; }
}
But the join table doesn't exist in my database. Can anyone see what I'm doing wrong?
Thanks

Excluding properties from a viewmodel

I have a viewmodel that contains a CustomerModel e.g.
public class MyAccountViewModel
{
public CustomerModel Customer { get; set; }
public LoginModel Login { get; set; }
public ICollection<AuthenticationClientData> Clients { get; set; }
public bool HasLocalPassword { get; set; }
public LocalPasswordModel Password { get; set; }
}
[DataContract]
public class CustomerModel
{
[DataMember]
public Guid CustomerBusinessId { get; set; }
[DataMember(IsRequired = true)]
[Required(ErrorMessage = "First Name is required")]
[Display(Name = "First Name")]
public string FirstName { get; set; }
[DataMember(IsRequired = true)]
[Required(ErrorMessage = "Last Name is required")]
[Display(Name = "Last Name")]
public string LastName { get; set; }
[DataMember]
public string FullName
{
get { return string.Format("{0} {1}", FirstName, LastName); }
}
[DataMember]
public string Identity { get; set; }
[DataMember(IsRequired = true)]
[Required(ErrorMessage = "Email is required")]
public string Email { get; set; }
[DataMember]
[Display(Name = "Birth Date")]
public DateTime? BirthDate { get; set; }
[DataMember]
public string Mobile { get; set; }
[DataMember]
public string Phone { get; set; }
[DataMember]
public string Twitter { get; set; }
[DataMember]
[Display(Name = "Facebook")]
public string FaceBook { get; set; }
[DataMember]
public string WebSite { get; set; }
[DataMember]
public string Blog { get; set; }
}
My CustomerModel object contains a property "CustomerBusinessId" is it possible for my viewmodel to exclude this property so I am only returning the required fields to the view?

Resources