Problems with Code First Migration and SQL Server Management Studio - c#

Having a problem with my database for an application I'm developing. I have two classes - House and Donation. A Donation needs to have a House associated with it.
public class House
{
[Key]
public int HouseId { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string AddressLine3 { get; set; }
}
public class Donation
{
[Key]
public int DonationId { get; set; }
public string TypeOfDonation { get; set; }
public decimal Amount { get; set; }
[ForeignKey("Church")]
public int ChurchId { get; set; }
[ForeignKey("House")]
public int HouseId { get; set; }
public virtual House House { get; set; }
public virtual Church Church { get; set; }
}
I've used Code First Migrations multiple times and its worked but I'm getting two errors. The first one I've noticed is on SQL Server Studio with Donation. It comes up with Invalid Column Name for all of them
Then, when I run the application and attempt to associate a Donation with a House, I get this error The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.Donation_dbo.House_HouseId". The conflict occurred in database "ChurchDatabase", table "dbo.House", column 'HouseId'".
Here's the Create in my DonationController where I get that error:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "DonationId,HouseId,TypeOfDonation,Amount,ChurchId")] Donation donation)
{
if (ModelState.IsValid)
{
db.Donations.Add(donation);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.ChurchId = new SelectList(db.Churches, "ChurchId", "Name", donation.ChurchId);
return View(donation);
}
Anyone have any idea what is going on? Its been wrecking my head

Found my problem, it was in my View:
<div class="form-group">
#Html.LabelFor(model => model.House.HouseId, "Address", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.House.HouseId, new { id = "HouseId" })
#Html.ValidationMessageFor(model => model.House.HouseId, "", new { #class = "text-danger" })
</div>
</div>
It needed to be:
<div class="form-group">
#Html.LabelFor(model => model.HouseId, "Address", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.HouseId, new { id = "HouseId" })
#Html.ValidationMessageFor(model => model.HouseId, "", new { #class = "text-danger" })
</div>
</div>
I was stupidly putting down House.HouseId when it didn't need the House bit

Related

How can I make an ASP.NET MVC DateTime picker form field display a message if datetime is taken?

I have a form that works with entity framework. This is my model:
public class CarModel
{
public int id { get; set; }
[Required]
[DisplayName ("Make")]
public string Maker { get; set; }
[Required]
public string Model { get; set; }
[Required]
public string Year { get; set; }
[Required]
public string Engine{ get; set; }
[Required]
public string VIN { get; set; }
[DisplayName("Date and Time")]
public DateTime Date { get; set; }
public string Work { get; set; }
}
And this is the view:
<div class="form-group">
#Html.LabelFor(model => model.Date, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Date, new { htmlAttributes = new { #class = "form-control" , type = "datetime-local" } })
<label>Please keep in mind our working hours are <br>9:00-17:00 Monday to Friday</label>
#Html.ValidationMessageFor(model => model.Date, "", new { #class = "text-danger" })
</div>
</div>
So as you can see, I have a DateTime field in the form. When someone inserts date and time that is already "taken", I want the program to display a view with the following text: "we're sorry but the date and time are already taken". What is the shortest way I can do that?
a Simple way for get this work in Your Controller
public ActionResult ActionResult(CarModel vm)
{
if (ModelState.IsValid)
{
if (_dbcontext.Car.Any(x => x.Date == vm.Date))
{
ModelState.AddModelError("Date ", "we're sorry but the date and time are already taken");
return View(vm);
}
// other works such as Save Data
}
return View(vm);
}
I don't think we can use '#Html.Validation' for this. Instead, You can create an another div with the error message you want to throw and display it if the date/time is not available.

ASP.NET MVC ViewModels to combine many-to-many model relationship to View

I am building the classic movie catalog project.
I have a many-to-many with movies and genres so that I can list the genres in movies and vice-versa, etc.
I am having trouble doing that with my models. I can use models to relate one to view, but need ViewBag to display the other.
I am a beginner and any help conquering advanced ViewModels would be greatly appreciated.
Ill use my create() movie method as an example:
My MovieController:
[Authorize(Roles = "Admin")]
[HttpGet]
public ActionResult Create()
{
ViewBag.Genres = db.Genres.Select(
g => new GenreToMovie
{
id = g.Id,
Name = g.Name,
Checked = false
}).ToList();
return View();
}
...
//List Genre Movies
private void MovieLister(Genre genre)
{
//Assign Movies to Genre List
ViewBag.Movies = db.Movies.Select(
m => new MovieToGenre
{
id = m.Id,
Title = m.Title,
Year = m.Year,
Checked = db.Genres.FirstOrDefault(g => g.Id == genre.Id).Movies.Any(movie => movie.Id == m.Id)
}).ToList();
My Movie Model:
namespace MovieSite.Models
{
public class Movie
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
public int Year { get; set; }
public virtual ICollection<Genre> Genres { get; set; }
public Movie() { }
public Movie(string title, int year)
{
Title = title;
Year = year;
Genres = new List<Genre>();
}
}
}
My MovieViewModels (A bad name I'm sure, its where I keep my GenreTomMovie ViewModel:
namespace MovieSite.Models
{
//Assign Genres to Movies
public class GenreToMovie
{
public int id { get; set; }
public string Name { get; set; }
public bool Checked { get; set; }
}
//Assign Movies to Genres
public class MovieToGenre
{
public int id { get; set; }
public string Title { get; set; }
public int Year { get; set; }
public bool Checked { get; set; }
}
public class MovieViewModel
{
public int MovieID;
public string Title { get; set; }
public int Year { get; set; }
public MovieViewModel() { }
public MovieViewModel(int id, string title, int year)
{
MovieID = id;
Title = title;
Year = year;
}
}
}
My Create View:
#model MovieSite.Models.Movie
#{
ViewBag.Title = "Create Movie";
}
<h2>Add Movie</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<label style="color:red" id="errormsg"></label>
<div class="form-group">
#Html.LabelFor(model => model.Title, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Title, new { htmlAttributes = new { #class = "form-control", id = "movieTitle" } })
#Html.ValidationMessageFor(model => model.Title, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Year, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Year, new { htmlAttributes = new { #class = "form-control", id = "movieYear" } })
#Html.ValidationMessageFor(model => model.Year, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Genres, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10" style="height:250px; width:400px; overflow-y:scroll">
<br />
#{
List<MovieSite.Models.GenreToMovie> moviegenres = ViewBag.Genres;
foreach (var genre in moviegenres.OrderBy(m => m.Name))
{
<ul style="padding:0px">
<input type="checkbox" name="SelectedGenres" value="#genre.id" #Html.Raw(genre.Checked ? "checked=\"checked\"" : "") />
#genre.Name
</ul>
}
}
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default"/>
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Manage")
</div>
You can see just below halfway on my views I have a viewbag:
#{
List<MovieSite.Models.GenreToMovie> moviegenres = ViewBag.Genres;
foreach (var genre in moviegenres.OrderBy(m => m.Name))
{
<ul style="padding:0px">
<input type="checkbox" name="SelectedGenres" value="#genre.id" #Html.Raw(genre.Checked ? "checked=\"checked\"" : "") />
#genre.Name
</ul>
}
}
To display my genres, and I don't want that. I have tried to make a number of viewmodels to combine data, but I get nowhere. I've been banging my head against the table for a couple days now and can't find a clear example online. Please Obi-Wan, you're my only hope.
I just need one clean example and I can figure this out. I just can't unlock it right now. Thanks for your time and help.
EDIT:
With the suggestion in the comments I made a viewmodel to pass through:
public class MovieAddVM
{
public int Id { get; set; }
public string Name { get; set; }
public int Year { get; set; }
public string Title { get; set; }
public bool Checked { get; set; }
public virtual ICollection<Genre> Genres { get; set; }
public MovieAddVM()
{
GenreList = new List<GenreToMovie>();
}
public List<GenreToMovie> GenreList { get; set; }
}
It registers with my views, but does not populate a list of genres. How do I query my genres and attribute that list to the viewmodel? I'm sorry I am very confused about all this.

MVC Post with complex types, model is empty

I have the following code to fill my model before posting it to my controller.
The list I'm iterating through is a list.
<div class="tab-content">
#*#foreach (var description in Model.Category.C_CategoryDescription)*#
#for (var i = 0; i < Model.Category.C_CategoryDescription.Count; i++)
{
<div id="#("tab" + #Model.Category.C_CategoryDescription.ToList()[i].ProductTypeId)" class="#(Model.Category.C_CategoryDescription.ToList()[i] == #Model.Category.C_CategoryDescription.First() ? "tab-active" : "tab")">
<div class="form-group ">
#Html.LabelFor(model => model.Category.C_CategoryDescription.ToList()[i].DescriptionTop, "Beskrivelse - Top", htmlAttributes: new {#class = "control-label col-md-2"})
<div class="col-md-10">
#Html.TextAreaFor(model => model.Category.C_CategoryDescription.ToList()[i].DescriptionTop, new {#class = "richText"})
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Category.C_CategoryDescription.ToList()[i].DescriptionBottom, "Beskrivelse - Bund", htmlAttributes: new {#class = "control-label col-md-2"})
<div class="col-md-10">
#Html.TextAreaFor(model => model.Category.C_CategoryDescription.ToList()[i].DescriptionBottom, new {#class = "richText"})
</div>
</div>
</div>
}
</div>
The HTML comes out fine. But as soon as I catch the post in my controller, the model is empty. Not NULL, but empty.
I read numerous articles saying that it points to a problem with the model binding.
I changed my code to reflect what's described: here
Still no dice.
Any help is appreciated.
EDIT: I changed my code according to this post.
My view now looks like this:
<div class="tab-content">
#Html.Partial("_Edit", Model.Category.C_CategoryDescription.ToList())
</div>
With a partial view looking like this:
#model IList<DataAccess.Plusbog.C_CategoryDescription>
#{
var productType = Model;
}
#for (var i = 0; i < productType.Count; i++)
{
<div id="#("tab" + #Model[i].ProductTypeId)" class="#(Model[i] == #Model.First() ? "tab-active" : "tab")">
<div class="form-group ">
#Html.LabelFor(model => productType[i].DescriptionTop, "Beskrivelse - Top", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextAreaFor(model => productType[i].DescriptionTop, new { #class = "richText" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => productType[i].DescriptionBottom, "Beskrivelse - Bund", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextAreaFor(model => productType[i].DescriptionBottom, new { #class = "richText" })
</div>
</div>
</div>
}
Same result, sadly.
EDIT:
Here's the models:
public class CategoryModel
{
public C_Category Category { get; set; }
public SelectList Categories { get; set; }
public SelectList ProductTypes { get; set; }
public String ISBNListToAddManually { get; set; }
public string Response { get; set; }
}
And the C_Category class:
public partial class C_Category
{
public C_Category()
{
this.C_CategoryDescription = new HashSet<C_CategoryDescription>();
this.Books = new HashSet<Books>();
this.ChildCategories = new HashSet<C_Category>();
this.Campaign = new HashSet<Campaign>();
this.Group = new HashSet<Group>();
}
public int Id { get; set; }
public Nullable<int> ParentCategoryId { get; set; }
public string Name { get; set; }
public bool Active { get; set; }
public string Slug { get; set; }
public string Keywords { get; set; }
public virtual ICollection<C_CategoryDescription> C_CategoryDescription { get; set; }
public virtual ICollection<Books> Books { get; set; }
public virtual ICollection<C_Category> ChildCategories { get; set; }
public virtual C_Category ParentCategory { get; set; }
public virtual ICollection<Campaign> Campaign { get; set; }
public virtual ICollection<Group> Group { get; set; }
}
And lastly, the C_CategoryDescription:
public partial class C_CategoryDescription
{
public int CategoryId { get; set; }
public int ProductTypeId { get; set; }
public string DescriptionTop { get; set; }
public string DescriptionBottom { get; set; }
public string MetaDescription { get; set; }
public string MetaKeywords { get; set; }
public string AlternativeTitle { get; set; }
public virtual C_Category C_Category { get; set; }
public virtual C_ProductType C_ProductType { get; set; }
}
Your code for generating the elements in the collection needs to be
#Html.TextAreaFor(m => m.Category.C_CategoryDescription[i].DescriptionTop, new {#class = "richText"})
which will generate the correct name attributes
<textarea name="Category.C_CategoryDescription[0].DescriptionTo" ... />
<textarea name="Category.C_CategoryDescription[1].DescriptionTo" ... />
Your current use a .ToList() is generating incorrect name attributes (not tested, but I assume its name="[0].DescriptionTo")
Alternatively you can use a custom EditorTemplate for the C_CategoryDescription model if you cannot change the collection to implement IList
In Views/Shared/EditorTemplates/C_CategoryDescription.cshtml (note the name of the file must match the name of the class)
#model yourAssembly.C_CategoryDescription
<div class="form-group ">
#Html.LabelFor(m => m.DescriptionTop, "Beskrivelse - Top", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextAreaFor(m => m.DescriptionTop, new { #class = "richText" })
<div>
</div>
....
and then in the main view, to generate the correct html for each item in the collection
#Html.EditorFor(m => m.Category.C_CategoryDescription)

Cascading dropdowns In MVC5 On demand load is giving 500 Error

I currently have a data model that was generated from an existing database utilizing Entity Framework 6 (ASP.NET MVC 5). I'm currently working with two data tables: Contracts and Employees. They both are related to the Company table, so each table has CompanyID as a foreign key. When I scaffolded the Create Contract view, it currently has drop down lists for EmployeeID and CompanyID. What I'm trying to do is have the user select the CompanyID and only show the Employees that are tied to that Company.
I've tried using jQuery's getJSON method, but it's returning a 500 error due to a circular reference as I'm returning a JSON serialized Employee object which has a reference to Company (causing the circular reference error).
The Employee Model:
public partial class Employee
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Employee()
{
this.Contracts = new HashSet<Contract>();
this.HoleLoggings = new HashSet<HoleLogging>();
}
public int EmployeeID { get; set; }
public int CompanyID { get; set; }
public string Name { get; set; }
public string Department { get; set; }
public virtual Company Company { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Contract> Contracts { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<HoleLogging> HoleLoggings { get; set; }
}
The Contracts Model:
public partial class Contract
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Contract()
{
this.ContractDetails = new HashSet<ContractDetail>();
this.Platforms = new HashSet<Platform>();
this.ShiftReports = new HashSet<ShiftReport>();
}
public int ContractID { get; set; }
public int EmployeeID { get; set; }
public int CompanyID { get; set; }
public Nullable<System.DateTime> StartDate { get; set; }
public Nullable<System.DateTime> EndDate { get; set; }
public Nullable<bool> IsApproved { get; set; }
public virtual Company Company { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<ContractDetail> ContractDetails { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Platform> Platforms { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<ShiftReport> ShiftReports { get; set; }
public virtual Employee Employee { get; set; }
}
Here's the ActionMethod in my Contracts Controller:
public JsonResult GetEmployees(int id)
{
List<Employee> employees = new List<Employee>();
var employeeList = from e in db.Employees
where (e.CompanyID == id)
select e.
employees.AddRange(employeeList);
return Json(employees, JsonRequestBehavior.AllowGet);
}
The View's form:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Contract</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.CompanyID, "CompanyID", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("CompanyID", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.CompanyID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.EmployeeID, "EmployeeID", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("EmployeeID", new SelectList(string.Empty, "Value", "Text"), "Please select an Employee", htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.EmployeeID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.StartDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.StartDate, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.StartDate, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.EndDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.EndDate, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.EndDate, "", new { #class = "text-danger" })
</div>
</div>
And the jQuery:
$(function () {
$("#CompanyID").change(function () {
$("#EmployeeID").empty();
var token = $('[name=__RequestVerificationToken]').val();
$.getJSON('#Url.Action("GetEmployees")', { id: $(this).val() }, function (employees) {
var employeesSelect = $("#EmployeeID");
$.each(employees, function (i, employee) {
employeesSelect.append($('<option/>', {
value: employee.value,
text: employee.text
}));
});
});
});
});
Any suggestions would be greatly appreciated!
Return a collection of anonymous objects containing just the properties you need (no point sending a whole lot of data to the client that you don't even use)
employees.AddRange(employeeList);
var data = employees.Select(e => new
{
value = e.EmployeeID,
text = e.Name
};
return Json(data, JsonRequestBehavior.AllowGet);

Populate a DropDownList with Users

I want to make my model to associate with a User from the Identity system in ASP.NET MVC 5, instead of an Employee. My problem is that I can't seem to figure out the magic behind #Html.DropDownList... I'm pulling my hair out. Here is my ViewModel:
public class TicketViewModel
{
[Display(Name="ID#")]
public int TicketId { get; set; }
public int EmployeeId { get; set; }
public int ShopId { get; set; }
public int UserId { get; set; }
public int ApplicationUserId { get; set; }
public string Description { get; set; }
public string Status { get; set; }
public EmployeeViewModel Employee { get; set; }
public ShopViewModel Shop { get; set; }
public TotsUser User { get; set; }
}
and the TicketController method:
// GET: /Ticket/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Ticket ticket = db.Tickets.Find(id);
if (ticket == null)
{
return HttpNotFound();
}
TicketViewModel ticketVM = Mapper.Map(ticket, new TicketViewModel());
ViewBag.EmployeeId = new SelectList(db.Employees, "EmployeeId", "Name", ticketVM.EmployeeId);
ViewBag.ShopId = new SelectList(db.Shops, "ShopId", "Name", ticketVM.ShopId);
ViewBag.UserListing = new SelectList(db.Users, "Id", "UserName", ticketVM.UserId);
return View(ticketVM);
}
The view (the part in question)
<div class="form-group">
#Html.LabelFor(model => model.EmployeeId, "EmployeeId", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("EmployeeId", String.Empty)
#Html.ValidationMessageFor(model => model.EmployeeId)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UserId, "UserId", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#* #Html.DropDownList("UserId", String.Empty) *#
#Html.DropDownList("UserId", #ViewBag.UserListing, null);
#Html.ValidationMessageFor(model => model.UserId)
</div>
</div>
I can't even explain how it even works with EmployeeId. This is the way that the scaffold generated it for my original model. It populates EmployeeId just fine. Can someone please explain the dark magic going on with the #Html.DropDownList helper and explain why I can't get the DropDownList to populate with anything?
you can try to change
ViewBag.UserListing = new SelectList(db.Users, "Id", "UserName", ticketVM.UserId);
to
ViewBag.UserId = new SelectList(db.Users, "Id", "UserName", ticketVM.UserId);
or change
#Html.DropDownList("UserId", #ViewBag.UserListing, null);
to
#Html.DropDownList("UserId", (SelectList)#ViewBag.UserListing);
This is incorrect no matter which method you use
#Html.DropDownList("UserId", #ViewBag.UserListing, null);
You have to tell the helper what type of object #ViewBag.UserListing is. In your case it would be (SelectList)#ViewBag.UserListing

Categories