Hi everyone so I am trying to create an application using asp.net mvc with a code first database that allows the users to be able to create a blog post with as many images as they wish.I am currently trying to have the image path in one table and the heading,body text in the other table along with a foreign key to the image path.So that I can create one post with multiple images. This is my first time using multiple tables and currently I am getting an error when it reaches this line context.SaveChanges(); in the save method when I am trying to create a post and save it to the db. Thank you for any help with this issue.
An exception of type 'System.Data.Entity.Infrastructure.DbUpdateException' occurred in EntityFramework.dll but was not handled in user code
Additional information: An error occurred while updating the entries. See the inner exception for details
I was able to get the program to work when I was using one table but it had this issue : https://i.sstatic.net/2uW6r.jpg
Here is the database Diagram :https://i.sstatic.net/9XE7T.jpg
Query that I tried to make but am not sure where to use in my code.
var query = db.PostModel.Where(x => x.PostID == PostId).Select(x => new
{
PostID = x.PostID,
ImageId = x.ImageModel.ImageId,
ImagePath = x.ImageModel.ImagePath,
Heading = x.PostModel.Heading,
PostBody = x.PostModel.PostBody
}).FirstOrDefault();
My program
View to Create posts
@model Crud.Models.PostModel
....
@using (Html.BeginForm("Create", "Home", null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<form action="" method="post" enctype="multipart/form-data">
@Html.LabelFor(model => model.ImageModel.ImagePath)
<input id="ImagePath" title="Upload a product image" multiple="multiple" type="file" name="files" />
@Html.LabelFor(model => model.Heading)
<input id="Heading" title="Heading" name="Heading" />
@Html.LabelFor(model => model.PostBody)
<input id="PostBody" title="PostBody" name="PostBody" />
<p><input type="submit" value="Create" /></p>
</form>
}
View to display posts
@model IEnumerable<Crud.Models.PostModel>
....
@foreach (var item in Model)
{
<div>@Html.DisplayFor(modelItem => item.Heading)</div>
<div>@Html.DisplayFor(modelItem => item.PostBody)</div>
<div><img class="img-thumbnail" width="150" height="150" src="/Img/@item.ImageModel.ImagePath" /></div>
}
Models
public partial class PostModel
{
[Key]
[HiddenInput(DisplayValue = false)]
public int PostID { get; set; }
public string Heading { get; set; }
public string PostBody { get; set; }
[ForeignKey("ImageModel")]
public int ImageId { get; set; }
public virtual ImageModel ImageModel { get; set; }
}
public class ImageModel
{
[Key]
public int ImageId { get; set; }
public string ImagePath { get; set; }
public string PostID { get; set; }
}
DBcontext
public class EFDbContext : DbContext
{
public DbSet<SchoolNewsModel> SchoolNews { get; set; }
public DbSet<PostModel> Posts { get; set; }
public DbSet<ImageModel> Images { get; set; }
}
Controller
public ViewResult Display()
{
return View(repository.Posts);
}
public ViewResult Create()
{
return View("Create", new PostModel());
}
[HttpPost]
public ActionResult Create(PostModel Image, IEnumerable<HttpPostedFileBase> files)
{
if (ModelState.IsValid)
{
foreach (var file in files)
{
PostModel post = new PostModel();
if (file.ContentLength > 0)
{
file.SaveAs(HttpContext.Server.MapPath("~/Img/") + file.FileName);
// post.ImagePath = file.FileName;
post.PostBody = post.PostBody;
post.Heading = post.Heading;
}
repository.Save(post);
}
}
return RedirectToAction("display");
}
public ViewResult PublicPostDisplay()
{
return View(repository.Posts);
}
Repository
public IEnumerable<PostModel> Posts
{
get { return context.Posts; }
}
public void Save(PostModel Image)
{
if (Image.PostID == 0)
{
context.Posts.Add(Image);
}
else
{
PostModel dbEntry = context.Posts.Find(Image.PostID);
if (dbEntry != null)
{
dbEntry.ImageModel.ImagePath = Image.ImageModel.ImagePath;
}
}
context.SaveChanges();
}
You need to include the full details of the error. Its the See the inner exception for details that will give you the relevant information. However that will probably not matter since your models and relationships are incorrect.
You want a PostModel
to have multiple ImageModel
so you need a one-many relationship and your PostModel
needs have the following property
public virtual ICollection<ImageModel> Images { get; set; }
and delete the int ImageId
and ImageModel ImageModel
properties. In addition the ImageModel
should contain public virtual PostModel Post { get; set; }
Your POST method to create a new PostModel
then becomes
[HttpPost]
public ActionResult Create(PostModel post, IEnumerable<HttpPostedFileBase> files)
{
if (!ModelState.IsValid)
{
return View(post);
}
foreach (var file in files)
{
if (file.ContentLength > 0)
{
file.SaveAs(HttpContext.Server.MapPath("~/Img/") + file.FileName);
// Initialize a new ImageModel, set its properties and add it to the PostModel
ImageModel image = new ImageModel()
{
ImagePath = file.FileName
};
post.Images.Add(image);
}
}
repository.Save(post);
return RedirectToAction("display");
}
There are however multiple other issues with your code that you should address.
<form>
tagPostVM
will include a property
IEnumerable<HttpPostedFileBase> Images
and in the view, bind to it
using @Html.TextBoxFor(m => m.Images, new { type = "file", multiple
= "multiple" })
[Required]
attribute on
Heading
and Body
. The you need to include
@Html.ValidationMessageFor()
for each property in the view.HtmlHelper
methods to generate form controls, e.g. @Html.TextBoxFor(..)
Guid
for the file name, and include a
additional property string DisplayName
in ImageModel
. Refer
this
answer
for an example of that approach.