I am building a web application using ASP .NET MVC5 and EF6. I have an one-to-one relationship defined as follows:
public class Client
{
public int ClientId { get; set; }
[Required]
public string Name { get; set; }
public Address Address { get; set; }
}
public class Address
{
[ForeignKey("Client")]
public int AddressId { get; set; }
[Required]
public string StreetName { get; set; }
public Client Client { get; set; }
}
Where Address is the dependent end. After enabling Migrations and updating the database, the two tables are created, in which, the Address table contains a ClientId column, as a result of the Foreign Key.
I then proceeded to generate the Controllers and Views for these classes.
For the Address, I'm trying to modify the Create/Edit methods and views to be able to add a new address and associate it to an existing Client, which is exactly what is done in this tutorial:
My AddressController was customized exactly as the tutorial suggests as well as the respective views. But upon accessing the Create page while running the web app, I am able to write a street name and choose from a drop down list a name for the client (which is what I want, display the client name and not the Id).
When hitting the create button, I get the following error:
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.Addresses_dbo.Clients_AddressId". The conflict occurred in database "myDb", table "dbo.Clients", column 'ClientId'. The statement has been terminated.
This leads me to believe that the Foreign Key ClientId is not being updated as it was supposed to be by selecting a name in the drop down list. I tried adding new clients without addresses associated to them but even by selecting a client without an associated address the error persists.
I also know that, ideally, the drop down list should actually only show the clients without any address associated to them but I don't know how to accomplish this.
Because I followed every step of the mentioned tutorial, I don't really know what I am doing wrong.
Any help would be extremely appreciated! If there is a need to post more code, I will do it, just didn't do it in order to shorten this already long post.
Update Code
AddressesController.cs
public class AddressesController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET: Addresses
public ActionResult Index()
{
var addresses = db.Addresses.Include(m => m.Client);
return View(addresses.ToList());
}
// GET: Addresses/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Address address = db.Addresses.Find(id);
if (address == null)
{
return HttpNotFound();
}
return View(address);
}
// GET: Address/Create
public ActionResult Create()
{
PopulateClientsDropDownList();
return View();
}
// POST: Addresses/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "AddressId,StreetName,ClientId")] Address address)
{
try
{
if (ModelState.IsValid)
{
db.Addresses.Add(addresses);
db.SaveChanges();
return RedirectToAction("Index");
}
}
catch (DataException dex)
{
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
ErrorSignal.FromCurrentContext().Raise(dex);
}
PopulateClientsDropDownList(address.ClientId);
return View(address);
}
// GET: Addresses/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Address address = db.Address.Find(id);
if (address == null)
{
return HttpNotFound();
}
PopulateClientsDropDownList(address.ClientId);
return View(address);
}
// POST: Addresses/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost, ActionName("Edit")]
[ValidateAntiForgeryToken]
public ActionResult EditPost(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var addressToUpdate = db.Addresses.Find(id);
if (TryUpdateModel(addressToUpdate, "",
new string[] { "StreetName", "ClientId" }))
{
try
{
db.SaveChanges();
return RedirectToAction("Index");
}
catch (RetryLimitExceededException dex)
{
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
ErrorSignal.FromCurrentContext().Raise(dex);
}
}
PopulateAddressesDropDownList(addressToUpdate.ClientId);
return View(addressToUpdate);
}
private void PopulateClientsDropDownList(object selectedClient = null)
{
var clientsQuery = from d in db.Clients
orderby d.Name
select d;
ViewBag.ClientId = new SelectList(clientsQuery, "ClientId", "Name", selectedClient);
}
}
Create.cshtml (Shortened)
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Addresses</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@*<div class="form-group">
@Html.LabelFor(model => model.AddressId, "AddressId", htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("AddressId", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.AddressId, "", new { @class = "text-danger" })
</div>
</div>*@
<div class="form-group">
@Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2" for="ClientId">Client Name</label>
<div class="col-md-10">
@Html.DropDownList("ClientId", null, htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.ClientId, "", new { @class = "text-danger" })
</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>
}