Issue with One to Many on MVC - asp.net-mvc

New to EF, MVC, and databases in general. If this is overly obvious just tell me what this is called exactly and I'd be glad to look it up on here.
I'm not able to apply information calculated from my Foreign Key to my Primary key.
In other words: I'm trying to calculate and apply a new AmountMade by a booth each time we "Sell" an Antique.
Booth Model:
public class Booth
{
public Booth()
{
Antiques = new List<Antique>();
}
[Required]
public int BoothId { get; set; }
[Required]
public string Owner { get; set; }
public double AmountMade { get; set; }
public Antique Antique {get;set;}
public virtual ICollection<Antique> Antiques{get;set;}
}
Antique Model:
public class Antique
{
[Required]
public int AntiqueId { get; set; }
[Required]
public string ItemName { get; set; }
[Required]
public double Price { get; set; }
public bool Sold { get; set; }
public int BoothId { get; set; }
[ForeignKey("BoothId")]
public virtual Booth Booth { get; set; }
}
AntiquesController:
// GET: Antiques/Sell/5
public ActionResult Sell(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Antique antique = db.Antiques.Find(id);
antique.Booth.AmountMade = antique.Booth.AmountMade + antique.Price; //Price of antique is added to Amount made
if (antique == null)
{
return HttpNotFound();
}
ViewBag.BoothId = new SelectList(db.Booths, "BoothId", "Owner", antique.BoothId);
return View(antique);
}
// POST: Antiques/Sell/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Sell([Bind(Include = "AntiqueId,ItemName,Price,BoothId")] Antique antique)
{
if (ModelState.IsValid)
{
db.Entry(antique).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
antique.Sold = true; //Mark as sold
ViewBag.BoothId = new SelectList(db.Booths, "BoothId", "Owner", antique.BoothId);
antique.Booth.AmountMade = antique.Booth.AmountMade + antique.Price; //Price of antique is added to Amount made
return View(antique);
}

This synchronization happens after Db.SaveChanges() is called, but I'm not sure can it be done before that by calling some other method.

Related

How do I use an edit viewmodel in MVC?

I have been struggling with this for some time. I have a model and an edit view model so I can allow the user to both see the image that was uploaded before and upload a replacement. Everything works fine until I get to the db.Entry portion. The error is:
The entity type EditCardViewModel is not part of the model for the current context.
If I try to add EditCardViewModel to the DbContext, it wants a key and a table, which isn't going to happen. The ViewModel is just a way to pass data. How do I tell it to use the Cards context when saving from this ViewModel?
Controller Edit Get:
public ActionResult Edit(int id = 0)
{
Card card = db.Cards.Find(id);
ViewData["Abilities"] = card.CardAbilities.Select(a => a.AbilityID);
if (card == null)
{
return HttpNotFound();
}
var editview = new EditCardViewModel(card);
{
}
return View(editview);
}
Controller Edit Post:
[HttpPost]
public ActionResult Edit(EditCardViewModel card)
{
if (ModelState.IsValid)
{
if(card.ImageUpload != null)
{
string savedFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Images");
savedFileName = Path.Combine(savedFileName, Path.GetFileName(card.ImageUpload.FileName));
card.ImageUpload.SaveAs(savedFileName);
card.Cards.ImageUrl = "\\Images\\" + Path.GetFileName(card.ImageUpload.FileName);
}
db.Entry(card).State = EntityState.Modified; //ERROR - Entity Type is not part of context
db.SaveChanges();
Edit ViewModel:
public class EditCardViewModel
{
public Card Cards { get; set; }
public HttpPostedFileBase ImageUpload { get; set; }
public IEnumerable<SelectListItem> Abilities { get; set; }
public int[] SelectedAbilities { get; set; }
public IEnumerable<SelectListItem> Rarities { get; set; }
public int SelectedRarities { get; set; }
public IEnumerable<SelectListItem> MainTypes { get; set; }
public int SelectedMainTypes { get; set; }
public IEnumerable<SelectListItem> SubTypes { get; set; }
public int SelectedSubTypes { get; set; }
public IEnumerable<SelectList> CardSets { get; set; }
public int SelectedCardSets { get; set; }
public Rarity Rarity { get; set; }
public MainType MainType { get; set; }
public SubType SubType { get; set; }
public CardSet CardSet { get; set; }
public EditCardViewModel() { } //NEEDED OR PARAMETERLESS CONSTRUCTOR ERROR
public EditCardViewModel(Card card) //NEEDED OR CANNOT PASS CARD MODEL
{
Cards = card;
}
}
The problem is that your view model is not recognised by Entity Framework - it has no idea that EditCardViewModel is meant to be a representation of a Card. It's a bit unclear from your view model exactly what you are doing with it but you either need to create a new Card object and use that:
var newCard = new Card
{
Id = card.Id //for example
};
Or possibly use the Cards property of your view model as that is of the correct type.

MVC Updates over values with NULL

This is probably very simple for most MVC programmers, so maybe you can help me out. I have a table called Images in the database with nine columns. On my UPDATE, I just have three I want to mess with (ImageName, ImagePath, CourseID). After I post back with UPDATE, it sets the other six columns to NULL. I'm not sure how to handle this in MVC.:
My ViewModel:
public class GalleryViewModel
{
public Image _image { get; set; }
}
My Model:
public partial class Image
{
public int ImageID { get; set; }
public string ImageName { get; set; }
public string ImagePath { get; set; }
public Nullable<int> CourseID { get; set; }
public string UserId { get; set; }
public Nullable<System.DateTime> CreateDate { get; set; }
public string ImageType { get; set; }
public string ImageSize { get; set; }
public string FriendlyName { get; set; }
public virtual Cours Cours { get; set; }
}
My Controller:
[HttpGet]
public ActionResult UploadImageEdit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var model = new GalleryViewModel
{
_image = db.Images.Find(id),
};
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult UploadImageEdit(GalleryViewModel galleryViewModel)
{
if (ModelState.IsValid)
{
db.Entry(galleryViewModel._image).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("UploadImageIndex");
}
return View(galleryViewModel);
}
After reading other examples and becoming more familiar with ViewModel to controller, I got the UPDATE to work by doing the following:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult UploadImageEdit(int id, GalleryViewModel galleryViewModel)
{
if (ModelState.IsValid)
{
var imageContext = db.Images.Find(id);
imageContext.FriendlyName = galleryViewModel._image.FriendlyName;
db.Entry(imageContext).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("UploadImageIndex");
}
return View(galleryViewModel);
}
I hope this helps other folks out!

MVC Automapper update

i tried to update my database table some fields
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(MemberTasks membertaskdetails)
{
if (ModelState.IsValid)
{
MemberTasks Mtasks = db.MemberTask.Find(membertaskdetails.id);
Mtasks.Taskid = membertaskdetails.Taskid;
Mtasks.status = membertaskdetails.status;
AutoMapper.Mapper.Map(membertaskdetails,Mtasks);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(membertaskdetails);
}
ViewModel
public class MemberTasks
{
[Key]
[Display(Name = "ID")]
public int id { get; set; }
[Display(Name = "Task ID")]
public int Taskid { get; set; }
[Display(Name = "Status")]
public int status { get; set; }
[Display(Name = "Created By")]
public string createdby { get; set; }
[Display(Name = "Team Lead")]
public string TeamLead { get; set; }
[Display(Name = "Note")]
public string Note { get; set; }
[Display(Name = "Members")]
public string Membersid { get; set; }
}
Code is executed successfully but the problem is remaining fields also updated with null value i have 6 columns i want to update 2 columns only.
Any help ?
Your source and destination object used in AutoMapper are of the same type (MemberTasks). That's not how AutoMapper is supposed to be used. AutoMapper is used to map between domain models and view models.
So you must have a view model containing the properties passed from the view:
public class MemberTasksViewModel
{
public int Id { get; set; }
public int Taskid { get; set; }
public int Status { get; set; }
}
and then:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(MemberTasksViewModel viewModel)
{
if (ModelState.IsValid)
{
MemberTasks domainModel = db.MemberTask.Find(viewModel.Id);
Mapper.Map(viewModel, domainModel);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel);
}

Saving Viewmodel data to the Database in ASP.NET MVC

I am new to ASP.net MVC and am using a viewmodel rather than viewbags to populate my dropdowns since I've seen most people recommend against them. I have a slick UI that does cascading dropdowns and autocompletes (not shown here) but I can't seem to get my data saved back to the database.
Models:
public partial class Car
{
public int CarID { get; set; }
public string CarName { get; set; }
public int ModelID { get; set; }
public int ManufacturerID { get; set; }
public int CarColorID { get; set; }
public Nullable<decimal> Price { get; set; }
public string Description { get; set; }
public virtual CarColor CarColor { get; set; }
public virtual Manufacturer Manufacturer { get; set; }
public virtual CarModel CarModel { get; set; }
}
public partial class CarColor
{
public CarColor()
{
this.Cars = new HashSet<Car>();
}
public int ColorID { get; set; }
public string ColorName { get; set; }
public virtual ICollection<Car> Cars { get; set; }
}
public partial class CarModel
{
public CarModel()
{
this.Cars = new HashSet<Car>();
}
public int CarModelID { get; set; }
public int ManufacturerID { get; set; }
public string CarModelName { get; set; }
public virtual ICollection<Car> Cars { get; set; }
public virtual Manufacturer Manufacturer { get; set; }
}
public partial class Manufacturer
{
public Manufacturer()
{
this.Cars = new HashSet<Car>();
this.Manufacturer1 = new HashSet<Manufacturer>();
this.CarModels = new HashSet<CarModel>();
}
public int ManufacturerID { get; set; }
public string ManufacturerName { get; set; }
public Nullable<int> ParentID { get; set; }
public virtual ICollection<Car> Cars { get; set; }
public virtual ICollection<Manufacturer> Manufacturer1 { get; set; }
public virtual Manufacturer Manufacturer2 { get; set; }
public virtual ICollection<CarModel> CarModels { get; set; }
}
ViewModel:
public class AnotherTestViewModel
{
public Car car { get; set; }
public IEnumerable<SelectListItem> CarModels { get; set; }
public IEnumerable<SelectListItem> Manufacturers { get; set; }
public IEnumerable<SelectListItem> CarColors { get; set; }
}
Controller:
public ActionResult Create()
{
var model = new AnotherTestViewModel();
using (new CarTestEntities())
{
model.CarModels = db.CarModels.ToList().Select(x => new SelectListItem
{
Value = x.CarModelID.ToString(),
Text = x.CarModelName
});
model.Manufacturers = db.Manufacturers.ToList().Select(x => new SelectListItem
{
Value = x.ManufacturerID.ToString(),
Text = x.ManufacturerName
});
model.CarColors = db.CarColors.ToList().Select(x => new SelectListItem
{
Value = x.ColorID.ToString(),
Text = x.ColorName
});
}
return View(model);
}
//
// POST: /AnotherTest/Create
[HttpPost]
public ActionResult Create(AnotherTestViewModel model)
{
if (ModelState.IsValid)
{
db.Entry(model).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Details", "AnotherTestViewModel", new { id = model.car.CarID });
}
return View();
}
I saw a few recommendations to use Automapper because EntityState.Modified won't work, but I'm not sure how to configure it because using the code below didn't work.
Mapper.CreateMap<AnotherTestViewModel, Car>();
Mapper.CreateMap<Car, AnotherTestViewModel>();
var newCar = Mapper.Map<AnotherTestViewModel, Car>(model);
Any ideas?
Your view model should not be interacting with the database. View Models should only be used in the presentation layer (user interface) - hence the term "View" model. You should have another model (data model) that interacts with your database. Then you should have some type of service layer that handles your conversion between your view model and your data model (and vice versa). Your data model is the model generated by Entity Framework (which I assume is what you are using). To handle updates to your database, you need to instantiate a data context, grab the data entity from your database, make changes to that entity, and call save changes all in that data context. The data context will keep track of all changes to your entities and apply the necessary changes to your database when you call "save changes".
Example:
public void UpdateCar(CarViewModel viewModel)
{
using (DataContext context = new DataContext())
{
CarEntity dataModel = context.CarEntities.where(x => x.Id == viewModel.Id).First();
dataModel.Name = viewModel.Name;
dataModel.Type = viewModel.Type;
context.SaveChanges();
}
}
In this example, context will keep track of any changes to "dataModel". When "context.SaveChanges" is called, those changes will automatically be applied to the database.

EF5 ASP.NET MVC 4 Linq query not returning anything & model property null -> Code First

Im having trouble linking my loaned items to my Library for each customer. It does it fine when it goes through the "AddToLibrary" method but when it comes to retreiving it, the medialibrary is empty and the query in the IEnumerable<Item> ItemsOnLoan method is returning null. This is a very basic ASP.NET MVC 4 application and im very new to this so its probably something silly ive missed out.
I just want to be able to add an item to the loaned items table, have the list of loaned items for each customer appear in their personal Library (defined in model) and then retreive the list of their items. Below is all the code and I am using a code first approach. Thank you :)
Model
public class Customer
{
public int Id { get; set; }
public string ForeName { get; set; }
public string SurName { get; set; }
public Address address { get; set; }
public string Email { get; set; }
public string Telephone { get; set; }
public string Mobile { get; set; }
public List<LoanedItem> Library { get; set; }
public Customer()
{
if (Library == null || Library.Count == 0)
{
Library = new List<LoanedItem>();
}
}
public IEnumerable<Item> ItemsOnLoan
{
get
{
var items = (from i in Library
where i.Customer.Id == this.Id
select i).OfType<item>();
return items;
}
}
}
Loaned Item model
public class LoanedItem
{
public int? Id { get; set; }
public Customer Customer { get; set; }
public MediaItem Item { get; set; }
}
ItemController --> adding to library method
public ActionResult AddToLibrary(int id)
{
Item libraryItem = db.Items.Find(id);
Customer c = db.Customers.Find(1);
LoanedItem newLoanGame = new LoanedItem()
{
Customer = c,
Item = libraryItem
};
db.LoanedItems.Add(newLoanGame);
db.SaveChanges();
return RedirectToAction("Index");
}
Customer Controller
public ActionResult ViewProfile(int id = 1)
{
Customer c = db.Customers.Find(id);
if (c == null)
{
return HttpNotFound();
}
return View(c);
}
public ActionResult GetLibraryItems(int id = 1)
{
var items = db.Customers.Find(id).ItemsOnLoan;
return View(items);
}
Context
public class LibraryContext : DbContext
{
public DbSet<Address> Addresses { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<LoanedItem> LoanedItems { get; set; }
public DbSet<Item> Items { get; set; }
public LibraryContext()
: base("LbContext")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new CustomerConfiguration());
modelBuilder.Configurations.Add(new LoanedItemConfiguration());
modelBuilder.Entity<Item>();
modelBuilder.Entity<Address>();
base.OnModelCreating(modelBuilder);
}
}
Assuming that Proxy generation is enabled try this:
public class Customer
{
public int Id { get; set; }
public string ForeName { get; set; }
public string SurName { get; set; }
public Address address { get; set; }
public string Email { get; set; }
public string Telephone { get; set; }
public string Mobile { get; set; }
public virtual ICollection<LoanedItem> ItemsOnLoan { get; set; }
public Customer()
{
}
}
using this to acccess:
public ActionResult GetLibraryItems(int id = 1)
{
var customer = db.Customers.Find(id);
if (customer != null)
{
var items = customer.ItemsOnLoan;
return View(items);
}
//handle not found or throw an exception
throw new Exception();
}
follow this link for more information on Proxies and Lazy Loading.

Resources