I have two models, a code model and a tag model which are linked by a many to many relationship. I am trying to add a code entry that includes a possible selection of many tags using a view model (using check boxes for the tags in my view). I am getting the error:
The model item passed into the dictionary is of type ‘System.Collections.Generic.List’1[StoRed.Models.Code]’, but this dictionary requires a model item of type ‘System.Collections.Generic.IEnumerable`1[StoRed.Models.CodeTagViewModel]’.
It feels like I need to somehow convert my data to the acceptable format before trying to save it into the table but I’m new to MVC and I am having trouble finding any useful information on the internet about my specific problem. Any help would be greatly appreciated.
The code model
public class Code
{
[Key]
public int CodeID { get; set; }
[Required]
[StringLength(30)]
public string Title { get; set; }
[Required]
[StringLength(150)]
public string Description { get; set; }
public DateTime DateAdded { get; set; }
public DateTime LastUpdated { get; set; }
[Required]
[StringLength(30)]
public string Project { get; set; }
[Required]
[StringLength(30)]
public string CMS { get; set; }
public int DotNetVersion { get; set; }
[Required]
[StringLength(150)]
public string Dependencies { get; set; }
[StringLength(30)]
public string Author { get; set; }
public string CodeFile { get; set; }
[Required]
[StringLength(100)]
public string TFSLocation { get; set; }
////Creates a relationship in the DB with Tag
//[ForeignKey("TagID")]
public virtual ICollection<Tag> Tags { get; set; }
////Purely for API
//[Required]
public int TagID { get; set; }
}
The Tag model
public class Tag
{
[Key]
public int TagID { get; set; }
[Required]
[StringLength(30)]
public string TagName { get; set; }
public virtual ICollection<Code> Code { get; set; }
}
The context
public class Context : DbContext
{
public DbSet<Code> Code { get; set; }
public DbSet<Tag> Tags { get; set; }
}
The view model
public class CodeTagViewModel
{
public Tag Tag { get; set; }
public Tag TagID { get; set; }
public List<Tag> Tags { get; set; }
public int CodeID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public DateTime DateAdded { get; set; }
public DateTime LastUpdated { get; set; }
public string Project { get; set; }
public string CMS { get; set; }
public int DotNetVersion { get; set; }
public string Dependencies { get; set; }
public string Author { get; set; }
public string CodeFile { get; set; }
public string TFSLocation { get; set; }
}
Relevant part of the code controller
[HttpPost]
public ActionResult Create(CodeTagViewModel codeTagViewModel)
{
if (ModelState.IsValid)
{
Code code = new Code();
Tag tag = new Tag();
var codeTag = new CodeTagViewModel();
code.Title = codeTagViewModel.Title;
code.Description = codeTagViewModel.Description;
code.DateAdded = codeTagViewModel.DateAdded;
code.LastUpdated = codeTagViewModel.LastUpdated;
code.Project = codeTagViewModel.Project;
code.CMS = codeTagViewModel.CMS;
code.DotNetVersion = codeTagViewModel.DotNetVersion;
code.Dependencies = codeTagViewModel.Dependencies;
code.Author = codeTagViewModel.Author;
code.CodeFile = codeTagViewModel.CodeFile;
code.TFSLocation = codeTagViewModel.TFSLocation;
code.Tags = codeTagViewModel.Tags;
db.Code.Add(code);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(codeTagViewModel);
}
Your best bet is to create some kind of provider/manager/service/factory/handler – choose a name that makes most sense in terms of the job it is doing within the flow of data through your system – that is responsible for taking the ViewModel and mapping the properties of the ViewModel into an instance of the domain model before persisting the domain model to the data store, either itself or by passing the hydrated domain model to a repository layer. You can either do this manually or by using something like AutoMapper. Here’s a quick manual example:
Create a
CommandHandlersfolder in your web project with the interface and dependant handler:Then in your controller, inject the ICodeCommandHandler in via constructor injection, the same as you do with the repository in the
CodeCommandHandler:To keep the
Repositorynice and simple, here’s how that could look:I’ve not gone into detail about the dependency injection side of things as that wasn’t part of the question but this should give you an idea of where to start