I am trying to learn ASP.net by making an e-commerce site. I am trying to set up the ability to create Items and assign Images to the item being created via File Upload.
I managed to get the multiple file upload working, but only to the content/Images folder. I cant figure out out to marry this to the creation of Items so you can assign multiple images to an Item all in the creation of the item.
It would be a fair to say I dont know where to go from here and would appreciate any help.
Item Model Class: Table in the database to store each item. Is referenced from the Images Table with a 1 to many relationship.
public class Item
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ItemId { get; set; }
public int CategoryId { get; set; }
public int DesignerId { get; set; }
public int ImageId { get; set; }
[Required]
[MaxLength(250)]
public string ItemName { get; set; }
[Required]
[Range(0,9999)]
public decimal ItemPrice { get; set; }
[MaxLength(1000)]
public string ItemDescription { get; set; }
[Range(4,22)]
public int ItemSize { get; set; }
[Column("CategoryId")]
public virtual List<Category> Category { get; set; }
public virtual List<OrderDetail> OrderDetails { get; set; }
public virtual List<Image> Images { get; set; }
}
Image Model Class: Stores the URL for each Image in the content Directory of the site. Can have many images for each Item.
public class Image
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ImageId { get; set; }
[Required]
public string ImageURL { get; set; }
[Required]
public string ItemId { get; set; }
//Files Being Uploaded by the User
public IEnumerable<HttpPostedFileBase> Files { get; set; }
[Column("ItemId")]
public virtual List<Item> Item { get; set; }
}
Store Manager Controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Item item,HttpPostedFileBase file)
{
if (ModelState.IsValid)
{
//The below successfully saves the file to the content folder when separated into the Index Action.
foreach (var f in item.Files)
{
if (file.ContentLength > 0)
{
var fileName = Path.GetFileName(f.FileName);
var path = Path.Combine(Server.MapPath("~/Content/ItemImages/"+item), fileName);
file.SaveAs(path);
}
}
// The below also works when I dont have the Above in the Action.
db.Items.Add(item);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(item);
}
Create Item View
#model Project.Models.Item
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Item</legend>
<div class="editor-label">
#Html.LabelFor(model => model.ItemName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ItemName)
#Html.ValidationMessageFor(model => model.ItemName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ItemPrice)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ItemPrice)
#Html.ValidationMessageFor(model => model.ItemPrice)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ItemDescription)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ItemDescription)
#Html.ValidationMessageFor(model => model.ItemDescription)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ItemColour)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ItemColour)
#Html.ValidationMessageFor(model => model.ItemColour)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ItemSize)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ItemSize)
#Html.ValidationMessageFor(model => model.ItemSize)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
#using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div>
<table>
<tr>
<td>Files</td>
<td><input type="file" name="Files" id="Files" multiple/></td>
</tr>
<tr>
<td></td>
<td><input type="submit" name="submit" value="Upload" /></td>
</tr>
</table>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
So it looks like you're pretty close.
You just have to add the images to the item before adding it to the database.
Since you're using EF, it should be something similar to this
//in your action
//add the images to the item
item.Images.Add(new Image { ImageUrl = ... });
//you should be able to just insert the whole entity graph here
db.Items.Add(item);
db.SaveChanges();
Something like that I think is what you're looking for.
Also in your model constructor normally I think you want to initalize those lists so you don't get null reference execeptions when doing something like the above
public class Item
{
public Item()
{
this.Images = new List<Image>();
}
//...
}
Related
I have the following ViewModel:
public class ActivityReportViewModel
{
public Dictionary<int, List<string>> Periods { get; set; }
public List<Project> Projects { get; set; }
public List<Templates> Templates { get; set; }
public DateTime TimePeriod { get; set; }
}
public class Project
{
public string Customer { get; set; }
public string ProjectNumber { get; set; }
public string ProjectDescription { get; set; }
public bool IsSelected { get; set; }
public int TemplateId { get; set; }
public bool XLSX { get; set; }
public bool PDF { get; set; }
}
I fill this ViewModel in my controller and then send it to my Create view, which works fine and the values of the Projects property are all there. However, when I postback the data to the server, the values are gone. I tried supplying HiddenFields to all properties of each Project to no avail. Here's my relevant view markup:
<div>
#Html.LabelFor(model => model.Projects, htmlAttributes: new { #class = "ms-Label" })
<ul class="ms-List" style="list-style:none;">
#for (int x = 0; x < Model.Projects.Count; x++)
{
<li class="ms-ListItem">
<span class="ms-ListItem-primaryText">#Model.Projects[x].ProjectDescription</span>
<span class="ms-ListItem-secondaryText">#Model.Projects[x].Customer</span>
<span class="ms-ListItem-tertiaryText">#Model.Projects[x].ProjectNumber</span>
#*<div class="ms-ListItem-selectionTarget js-toggleSelection"></div>*#
#Html.HiddenFor(m => Model.Projects[x].IsSelected)
#Html.HiddenFor(m => Model.Projects[x].ProjectDescription)
#Html.HiddenFor(m => Model.Projects[x].Customer)
#Html.HiddenFor(m => Model.Projects[x].ProjectNumber)
#Html.HiddenFor(m => Model.Projects[x].XLSX)
#Html.HiddenFor(m => Model.Projects[x].PDF)
<div class="ms-Dropdown">
<i class="ms-Dropdown-caretDown ms-Icon ms-Icon--caretDown"></i>
#Html.DropDownListFor(m => m.Projects[x].TemplateId, new SelectList(Model.Templates, "Id", "Name"), new { #class = "ms-Dropdown-select" })
</div>
<div class="ms-ChoiceField">
<input id="excel+#Model.Projects[x].ProjectNumber" class="ms-ChoiceField-input" value="#Model.Projects[x].XLSX" type="checkbox">
<label for="excel+#Model.Projects[x].ProjectNumber" class="ms-ChoiceField-field"><span class="ms-Label is-required">Excel</span></label>
</div>
<div class="ms-ChoiceField">
<input id="pdf+#Model.Projects[x].ProjectNumber" class="ms-ChoiceField-input" value="#Model.Projects[x].PDF" type="checkbox">
<label for="pdf+#Model.Projects[x].ProjectNumber" class="ms-ChoiceField-field"><span class="ms-Label is-required">PDF</span></label>
</div>
</li>
}
</ul>
<div>
#Html.ValidationMessageFor(model => model.Projects, "", new { #class = "text-danger" })
</div>
</div>
EDIT:
Here's my POST action method:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ActivityReportViewModel report)
{
using (AppContainer _db = new AppContainer())
{
if (ModelState.IsValid)
{
_db.SaveChanges();
return RedirectToAction("Index");
}
return PartialView(report);
}
}
The DefaultViewModel Binder uses the HTML attribute name to determine which property to bind back to on the server. I cannot see name attribute specified on your input element. Please specify name attribute on the elements you wish to post back to the server with the property of the view model.
Specifiy name attribute as below. Notice I have added name attribute with value as the property of your view model
<input id="excel+#Model.Projects[x].ProjectNumber" class="ms-ChoiceField-input" name="#Model.Projects[x].ProjectNumber" value="#Model.Projects[x].XLSX" type="checkbox">
I'm trying to create a basic forum in ASP.NET MVC 5 and I am really stuck at a "The INSERT statement conflicted with the FOREIGN KEY constraint" error.
I will post my class and controller for this assignment and an image that illustrates how I want this to work.
Thread.cs
namespace BlogProject.Models
{
public class Thread
{
[Key]
public int ThreadId { get; set; }
public DateTime? PostDate { get; set; }
public string ThreadText { get; set; }
public string ThreadTitle { get; set; }
public virtual ApplicationUser UserProfile { get; set; }
public string GetUserName { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string PostTitle { get; set; }
public string PostText { get; set; }
public DateTime? PostDate { get; set; }
public virtual ApplicationUser UserProfile { get; set; }
public virtual Thread Thread { get; set; }
//[ForeignKey("Thread")]
public int ThreadId { get; set; }
}
}
PostsController.cs
// POST: Posts/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 = "PostId,PostTitle,PostText,PostDate,ThreadId")] Post post,Thread thread)
{
if (ModelState.IsValid)
{
db.Posts.Add(post);
db.SaveChanges();
return RedirectToAction("Threads");
}
ViewBag.ThreadId = new SelectList(db.Threads, "ThreadId", "ThreadText", post.ThreadId);
return View("Details");
}
This is how I want it to work:
Forum goal
If you think the information here is not sufficient then tell me and I will add more.
Thanks in advance!
UPDATE EDIT:
Sorry, forgot to include my Views
Details.cshtml, this is where my Threads go
#model BlogProject.Models.Thread
#{
ViewBag.Title = "Details";
}
<h2>Details</h2>
<div class="container">
<h3>Current thread: #Html.DisplayFor(model => model.ThreadTitle), Posted by: #Html.DisplayFor(modelItem => Model.GetUserName)</h3>
<div class="panel panel-default">
<div class="panel-body">
<div class="col-lg-2">
<div class="thumbnail">
<img class="img-responsive user-photo" src="https://ssl.gstatic.com/accounts/ui/avatar_2x.png">
</div>
</div>
<div class="well-lg">
<div class="col-lg-10">
#Html.DisplayFor(model => model.ThreadText)
</div>
</div>
</div>
</div>
<p class="text-center">
#Html.ActionLink("Reply to this thread","Create","Posts")
#Html.ActionLink("Back to List", "Index")
</p>
</div>
Posts/Create.cshtml (Partial view)
#model BlogProject.Models.Post
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Post</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.PostText, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PostText, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.PostText, "", 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>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
I will post more Views if needed. Sorry for taking so long to answer, I'm mostly lying down on the couch sleeping today.
First change the Postmodel because your not assigning Primary Key and foreign Key
public class Post
{
[Key]
public int PostId { get; set; }
.
public int ThreadId { get; set; }
[ForeignKey("ThreadId")]
public virtual Thread Thread { get; set; }
}
In the controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Thread thread)
Because in the view page you have used only
#model BlogProject.Models.Thread
The post object will be null and try 'thread'
db.Posts.Add(post);
hope this helps
In EF I have two tables (parent is Office- child is Employee), I m adding records to Employee with reference of existing Office record but I guess because of my wrong configuration EF is behaving wearied.
Instead of using Office table's existing record, it add a new records in Office and use new record's id as a foreign key in child records and then create child records.
Here are my Models:
public class Office
{
public int OfficeId{ get; set; }
public string Name { get; set; }
public virtual IEnumerable<Employee> Employees{ get; set; }
}
public class Employee
{
public int EmployeeID{ get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DOB { get; set; }
[NotMapped]
public int Age { get { return DOB.YearsFromUtcDateTillToday(); } }
[NotMapped]
public string FullName { get { return string.Concat(FirstName, ' ', LastName); } }
public virtual Office Office { get; set; }
}
View is strongly typed of Employee here is view code:
#model Employee
#{
ViewBag.Title = "AddEmployee";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm(MVC.CodeTest.AddEmployee(),FormMethod.Post)) {
#Html.ValidationSummary(true)
#Html.HiddenFor(model=>model.Office.OfficID)
<fieldset>
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.DOB)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.DOB)
#Html.ValidationMessageFor(model => model.DOB)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.GPA)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.GPA)
#Html.ValidationMessageFor(model => model.GPA)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
My Controller Actions are the following:
public virtual ActionResult AddEmployee(int officeId)
{
Employee st = new Employee();
st.Office=new Office();
st.Office.OfficeID= officeId;
return View(st);
}
[HttpPost]
public virtual ActionResult AddEmployee(Employee objEmployee)
{
bool success= classEmployeeService.AddEmployee(objEmployee);
if (success)
{
return RedirectToAction("Index",objEmployee.Office.OfficeId);
}
else
{
ModelState.AddModelError("", "Error! Business rule violation, can't repeat surname");
}
return View(objEmployee);
}
My Finding:
In first action (without HttpPost) OfficeId is correct, 1 in this case
Checking html I came to know it is correct
But When pressing Save button 2nd action with HttpPost is executed OfficeId value is wrong, it is new Office record id (18, 19 or next record)
Please guide and help me.
As i see you've an problem with your Model Design. The Employee class should has a property to represent the foreign key of OfficeID.
public class Employee
{
public int EmployeeID{ get; set; }
public int OfficeID{ get; set; } // This what you need
// ...... the rest of class properties
}
Then just assign the Office Id to this property not to the Navigation property "Office"
Employee st = new Employee();
st.OfficeID= officeId;
And never use st.Office=new Office(); because this will add this object to the DbContext StateManager as "Added" and it'll add it as new record to the Database.
For registering a new customer I have several partials on my view which refer to corresponding tables in my database.
Primary keys are identity fields, that's why no IDs on the view. To insert a new customer I need to insert 3 occurrences of address(visiting, postal and contact person's), then insert a row for contract, contact_person(with using addressId from one of already inserted addresses) and finally proceed with inserting a new customer which will contain foreign keys referencing to just inserted visiting and postal addresses, contract and contact person.
Could you recommend the best/easiest way to pass the data from these partial views as objects to CustomerController and handle the objects there please?
Links to examples of handling similar situations will be also highly appreciated.
Image of my page:
http://i1345.photobucket.com/albums/p673/swell_daze/customer_registration_zps563341d0.png
Image of tables:
http://i1345.photobucket.com/albums/p673/swell_daze/tables_zpsc60b644a.png
View code:
#model CIM.Models.customer
<h2>Register new customer</h2>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>New customer registration</legend>
<fieldset class="span3">
<legend>Basic information</legend>
<div class="editor-label">
#Html.LabelFor(model => model.name, "Name")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.name)
#Html.ValidationMessageFor(model => model.name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.groupId, "Customer group")
</div>
<div class="editor-field">
#Html.DropDownList("groupId", String.Empty)
#Html.ValidationMessageFor(model => model.groupId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.status, "Status")
</div>
<div class="editor-field">
#Html.DropDownList("status")
#Html.ValidationMessageFor(model => model.status)
</div>
</fieldset>
<fieldset class="span3">
<legend>Visiting address</legend>
<div>
#{
Html.RenderPartial("AddressPartial");
}
</div>
</fieldset>
<fieldset style="width:270px">
<legend>Postal address</legend>
<div>
#{
Html.RenderPartial("AddressPartial");
}
</div>
</fieldset>
<fieldset class="span3">
<legend>Contract</legend>
<div>
#{
Html.RenderPartial("ContractPartial");
}
</div>
</fieldset>
<fieldset class="span3" style="width:540px">
<legend>Contact person</legend>
<div>
#{
Html.RenderPartial("ContactPersonPartial");
}
</div>
<p>
<input type="submit" class="btn btn-success" value="Submit" style="margin-right:1em"/>
#Html.ActionLink("Cancel", "Index", "Customer", new {#class="btn btn-danger", #type="button"})
</p>
</fieldset>
</fieldset>
}
you can wrap your view data in a viewmodel, then when you submit your data it will be mapped to your viewmodel, something like this:
Create a viewmodel:
public class MyViewModel
{
public string name { get; set; }
public string someprop1 { get; set; }
public string someprop2 { get; set; }
public MyAddress visitingaddress { get; set; }
public MyAddress postaladdress { get; set; }
public MyContactAddress contactaddress { get; set; }
}
public class MyAddress
{
public string town { get; set; }
public string street { get; set; }
public string housenumber { get; set; }
public string postalcode { get; set; }
}
public class MyContactAddress : MyAddress
{
public string firstname { get; set; }
public string lastname { get; set; }
public string email { get; set; }
public string phonenumber { get; set; }
}
Create your view just like you have done but by using your viewmodel instead of the model you are using now (CIM.Models.customer), and then in your partials, for example in the postal address partial view do something like this:
.......
#Html.EditorFor(x => x.postaladdress.town)
......
Create your controller actions by using your viewmodel:
public ActionResult Index()
{
MyViewModel vm = new MyViewModel();
//doing something here....
return View(vm);
}
[HttpPost]
public ActionResult Index(MyViewModel vm)
{
//save your data, here your viewmodel will be correctly filled
return View(vm);
}
hope this helps
I'm listing a series of items and i want top implement an option where you click and it add a child object for that entity, let me explain:
public class SupportItem
{
[Display(Name = "Categoría")]
[ConcurrencyCheck, Required]
public string Type { get; set; }
[Key, HiddenInput(DisplayValue = false)]
public int SupportItemId { get; set; }
[Display(Name = "Nombre")]
[ConcurrencyCheck,Required]
public string Name { get; set; }
[ConcurrencyCheck]
[Display(Name = "Descripción Corta")]
[DataType(DataType.MultilineText)]
[Required]
public string Description { get; set; }
[HiddenInput(DisplayValue = false)]
public virtual SupportItem Father { get; set; }
[Display(Name = "Descripción detallada")]
[DataType(DataType.MultilineText)]
[Required]
public string LongDescription { get; set; }
[HiddenInput(DisplayValue = false)]
public bool Children { get; set; }
}
Now as u can see, this entity has a Father which is of type SupporItem. Now what I want to do is to list them all and add an option which will let you easily add a child for that item you select, heres the view definition:
#model IEnumerable<Domain.Entities.SupportItem>
#{
ViewBag.Title = "IndexSupportItems";
Layout = "~/Views/Shared/_AdminLayout.cshtml";
}
<h2>Index Support Items</h2>
<p>
#Html.ActionLink("Crear nuevo item principal", "Create")
</p>
<table class="Grid">
<tr>
<th>
Tipo
</th>
<th>
Nombre
</th>
<th>
Descripción
</th>
<th>
Acciones
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>#item.Type</td>
#if(item.Children)
{
<td>#Html.ActionLink(item.Name,"ListChildren", new{item.SupportItemId})</td>
}
else
{<td>#item.Name</td>
}
<td>#item.Description</td>
<td>
#Html.ActionLink("Delete","DeleteSupportItem", new{item.Father.SupportItemId})<br />
#Html.ActionLink("Add subitem sub-item","AddSubitem", new{item.SupportItemId})<br />
#Html.ActionLink("Edit","EditSupportItem", new{item.SupportItemId})
</td>
</tr>
}
</table>
Now as you can see, the action link for doing this points to a method called AddSubitem, which is implemented as follows:
public ViewResult AddSubitem(int supportItemId)
{
SupportItem child = new SupportItem() { Father = repo.GetSupportItemFromId(supportItemId) };
return View(child);
}
As you can see, I recieve a supportItemId which is the id from the parent entitity (the one to whom i want to add the new child), find it on my database context and create the new object and point the Father object i just found. After doing that the view it returns is this:
#model Domain.Entities.SupportItem
#{
ViewBag.Title = "AddSubitem";
}
<h2>AddSubitem</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Support Item</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Type)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Type)
#Html.ValidationMessageFor(model => model.Type)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Description)
#Html.ValidationMessageFor(model => model.Description)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LongDescription)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LongDescription)
#Html.ValidationMessageFor(model => model.LongDescription)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
In this view, the user will set some of the variables such as name and description and then submit the object so I can persist it to the database, the problem is the object I get from this view has its fathers id as its own id and the Father attribute is null thus i end up updating the Father object to which i want to add a child with this method:
public bool SaveSupportItem(SupportItem supportItem)
{
bool retorno = false;
if (supportItem.SupportItemId == 0)
{
context.SupportItems.Add(supportItem);
supportItem.Father.Children = true;
retorno = true;
}
else
{
SupportItem itemDB = context.SupportItems.Find(supportItem.SupportItemId);
if (itemDB != null)
{
itemDB.Name = supportItem.Name;
itemDB.Type = supportItem.Type;
itemDB.LongDescription = supportItem.LongDescription;
itemDB.Description = supportItem.Description;
retorno = true;
}
}
context.SaveChanges();
return retorno;
}
What am I doing wrong here? why can't I create a new object?
Thanks for taking the time and reading this, any help will be really appreciated!
Well, try this:
Add this to your SupportItem class
public class SupportItem
{
[Key]
[HiddenInput(DisplayValue = false)]
[ForeignKey("Father"), DatabaseGenerated(DatabaseGeneratedOption.None)]
public int SupportItemId { get; set; }
public virtual Father Father { get; set; }
...................
...................
}
Then change:
#Html.ActionLink("Add subitem sub-item","AddSubitem", new{item.SupportItemId})<br />
to
#Html.ActionLink("Add subitem sub-item","AddSubitem", "Controller Name here" new{SupportItemId = #Model.FatherId})<br />
Also because we need FatherId here new{SupportItemId = #Model.FatherId}, the ActionLink needs to be in lets say Father view e.g in Father Details where only single Father is current or something as you have to associate the supportItem with to specific father.
Your controller might look like this, assuming that you are using a ViewModel:
[HttpGet]
public ActionResult CreateSuppo(int supportItemId)
{
var model = new CreateSupportItemViewModel ();
model.SupportItemId= supportItemId;
return View(model);
}
[HttpPost]
public ActionResult Create(CreateSupportItemViewModel viewModel)
{
if(ModelState.IsValid)
{
var father= db.Fathers.Single(f => f.FatherId == viewModel.SupportItemId);
var supportItem= new SupportItem();
supportItem.Name = viewModel.Name;
....................
.................
father.SupportItems.Add(supportItem);
db.SaveChanges();
}
return View(viewModel);
}