Add value to Parent when value is added to Child MVC - asp.net-mvc

I saw some questions and answers about adding a value to a child when add/update the parent, but my question is the opposite.
I have a model Component with a parent-child relationship:
public class Component
{
public virtual int ComponentId { get; set; }
public virtual string Type { get; set; }
public virtual string Name { get; set; }
public virtual Course Course { get; set; }
public virtual int ParentId { get; set; }
public virtual Component Parent { get; set; }
public virtual List<Component> Childs { get; set; }
public virtual List<Evaluation> Evaluations { get; set; }
}
And i need to give a grade to each child to each user.
I have this model:
public class Evaluation
{
public virtual int EvaluationId { get; set; }
public virtual int ComponentId { get; set; }
public virtual Component Component { get; set; }
public virtual int UserCourseId { get; set; }
public virtual UserCourse User { get; set; }
public virtual int Grade { get; set; }
}
And a view that gets a component selected and allows to choose the user and give a grade. It's only allowed to give a grade to the last child, and the grade of their parent would be the same grade of the child (the ideia is in the future to have more childs and the grade of the parent would be the sum of their grade). So i need to create a new row on the database with the same grade but with the parent id of the component selected.
I tried this code but it doesn't work:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Evaluation evaluation)
{
if (ModelState.IsValid)
{
if (evaluation.Component.ParentId != 0)
{
var nota = new Evaluation
{
ComponentId = evaluation.Component.ParentId,
UserCourseId = evaluation.UserCourseId,
Grade = evaluation.Grade
};
db.Evaluations.Add(nota);
db.SaveChanges();
}
db.Evaluations.Add(evaluation);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(evaluation);
}
(Note that this code can and probably is totally wrong)
How can i do this?
Thanks

After creating nota create a Component. something like this:
var nota = new Evaluation
{
ComponentId = evaluation.Component.ParentId,
UserCourseId = evaluation.UserCourseId,
Grade = evaluation.Grade
};
var component= new Component();
component.add(nota);
db.Components.Add(component);
db.SaveChanges();
You should see your nota also added to Evaluation table because of parent-child relationship.

Related

Not able to fetch data in one to one related data in MVC

I am not able to fetch the Centers Location where as I am able to save and update it it database. Its only fetching where I am facing problem
public class Club
{
public Club()
{
this.Memberships = new HashSet<Membership>();
this.People = new HashSet<Manager>();
this.Center = new Center();
}
public int ClubId { get; set; }
public string ClubName { get; set; }
public System.DateTime OpenDate { get; set; }
[ForeignKey("Center")]
public virtual Center Center { get; set; }
public virtual ICollection<Membership> Memberships { get; set; }
public virtual ICollection<Manager> People { get; set; }
}
My center model
public class Center
{
[Key,ForeignKey("Club")]
public int ClubId { get; set; }
public string Location { get; set; }
public virtual Club Club { get; set; }
}
and the index method is
public ActionResult Index()
{
return View(db.Clubs.ToList());
}
Your reference to Center is virtual, so it is lazy loaded. Try this instead:
return View(db.Clubs.Include(c => c.Center).ToList());
https://msdn.microsoft.com/en-us/data/jj574232.aspx#lazy
I noticed you're sending your entity model to the view. You may want to look into the viewmodel pattern and automapper. http://www.stevefenton.co.uk/Content/Blog/Date/201303/Blog/Why-You-Never-Expose-Your-Domain-Model-As-Your-MVC-Model/

Join two Models to display in webpage

I'm building an application using ASP.NET MVC4 with code first data migrations. I have an estimates model, a clients model, a DbContext, and a view model I created. I am wanting to display the company name in a drop down, with the company name tied to an estimate. I have a ClientId in both models. I also created a DbSet<> and that didn't work either when querying against it.
I tried to create a viewmodel that I thought I could simply query against and display through my controller. I'm not having any luck in getting this to work. After a day plus of looking on here and other places, I'm out of ideas.
How can I query/join the two models, or query the viewmodel to get the company name associated with the clientId? Thanks for the help.
Models:
public class Estimates
{
[Key]
public int EstimateId { get; set; }
public int ClientId { get; set; }
public decimal EstimateAmount { get; set; }
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MM/dd/yyyy}")]
public DateTime EstimateDate { get; set; }
public string EstimateNotes { get; set; }
}
public class Clients
{
[Key]
public int ClientId { get; set; }
public string CompanyName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
public ICollection<Estimates> Estimates { get; set; }
public ICollection<Contracts> Contracts { get; set; }
}
public class ClientEstimateViewModel
{
public Clients Clients { get; set; }
public Estimates Estimates { get; set; }
}
public class NovaDb : DbContext
{
public NovaDb(): base("DefaultConnection")
{
}
public DbSet<Clients> Clients { get; set; }
public DbSet<Estimates> Estimates { get; set; }
public DbSet<Contracts> Contracts { get; set; }
public DbSet<Invoices> Invoices { get; set; }
public DbSet<ClientEstimateViewModel> ClientViewModels { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Controller:
NovaDb _db = new NovaDb();
ClientEstimateViewModel ce = new ClientEstimateViewModel();
public ActionResult Index()
{
var model =
(from r in ce.Clients
join x in ce.Estimates
where
//var model =
// from r in _db.Clients
// orderby r.CompanyName ascending
// select r;
return View(model);
}
Because you've created the relationship between client & estimate in your models, you should be able to create a query like this:
var query = from c in _db.clients
select new ClientEstimateViewModel
{
Clients = c,
Estimates = c.Estimates
}
Although you'd have to change your model so Estimates was public List<Estimates> Estimates { get; set; }
This would give you a collection of ClientEstimateViewModel which you could then pass to your view

Populating navigation properties of navigation properties

How do I populate a navigation property with specific value?
I have 3 models, Game, UserTeam, User, defined below. I have a razor view which uses the model IEnumerable. This view loops over the Games, and within that loop, loops over the UserTeams. So far, so good.
Within the UserTeam loop, I want to access the User properties, but they are null. How do I populate the User navigation property for each UserTeam object? Do I need a constructor with a parameter in the UserTeam model?
Models
public class Game
{
public Game()
{
UserTeams = new HashSet<UserTeam>();
}
public int Id { get; set; }
public int CreatorId { get; set; }
public string Name { get; set; }
public int CurrentOrderPosition { get; set; }
public virtual UserProfile Creator { get; set; }
public virtual ICollection<UserTeam> UserTeams { get; set; }
}
public class UserTeam
{
public UserTeam()
{
User = new UserProfile();
}
public int Id { get; set; }
public int UserId { get; set; }
public int GameId { get; set; }
public int OrderPosition { get; set; }
public virtual UserProfile User { get; set; }
public virtual Game Game { get; set; }
public virtual IList<UserTeam_Player> UserTeam_Players { get; set; }
}
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string test { get; set; }
public UserProfile()
{
UserTeams = new HashSet<UserTeam>();
}
public virtual ICollection<UserTeam> UserTeams { get; set; }
[ForeignKey("CreatorId")]
public virtual ICollection<Game> Games { get; set; }
}
Loop in my Razor view (Model is IEnumerable)
#foreach (var item in Model) {
#foreach (var userteam in item.UserTeams) {
#Html.ActionLink("Join game as"+userteam.User.UserName, "JoinGame", new { gameid = item.Id, userid=userteam.UserId })
}
}
Method in my repository that returns the Games
public IEnumerable<Game> GetAllGames()
{
using (DataContext)
{
var gm = DataContext.Games.Include("UserTeams").ToList();
return gm;
}
}
You would need to include this in your repository method. If you are using eager loading then it would be something like
var gm = DataContext.Games
.Include(x => x.UserTeams)
.Include(x => x.UserTeams.Select(y => y.User))
.ToList();
I have not done this without using LINQ for my queries, but I assume it would be something like:
var gm = DataContext.Games.Include("UserTeams.User").ToList();
Hopefully this helps you out

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.

LINQ to entities against EF in many to many relationship

I'm using ASP.NET MVC4 EF CodeFirst.
Need help to write LINQ (to entities) code in Index action to get collection of Courses which are attended by selected student. The relationship is many to many with join table with payload.
//StudentController
//-----------------------
public ActionResult Index(int? id)
{
var viewModel = new StudentIndexViewModel();
viewModel.Students = db.Students;
if (id != null)
{
ViewBag.StudentId = id.Value;
// *************PROBLEM IN LINE DOWN. HOW TO MAKE COURSES COLLECTION?
viewModel.Courses = db.Courses
.Include(i => i.StudentsToCourses.Where(t => t.ObjStudent.FkStudentId == id.Value));
}
return View(viewModel);
}
The error I got is:
The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.
I have modeles (the third one is for join table with payload):
//MODEL CLASSES
//-------------
public class Student
{
public int StudentId { get; set; }
public string Name { get; set; }
public virtual ICollection<StudentToCourse> StudentsToCourses { get; set; }
}
public class Course
{
public int CourseId { get; set; }
public string Title { get; set; }
public virtual ICollection<StudentToCourse> StudentsToCourses { get; set; }
}
public class StudentToCourse
{
public int StudentToCourseId { get; set; }
public int FkStudentId { get; set; }
public int FkCourseId { get; set; }
public string Classroom { get; set; }
public virtual Student ObjStudent { get; set; }
public virtual Course ObjCourse { get; set; }
}
Then, here is modelview I need to pass to view
//VIEWMODEL CLASS
//---------------
public class StudentIndexViewModel
{
public IEnumerable<Student> Students { get; set; }
public IEnumerable<Course> Courses { get; set; }
public IEnumerable<StudentToCourse> StudentsToCourses { get; set; }
}
EF does not support conditional include's. You'll need to include all or nothing (ie no Whereinside the Include)
If you need to get the data for just certain relations, you can select it into an anonymous type, something like (the obviously untested);
var intermediary = (from course in db.Courses
from stc in course.StudentsToCourses
where stc.ObjStudent.FkStudentId == id.Value
select new {item, stc}).AsEnumerable();
Obviously, this will require some code changes, since it's no longer a straight forward Course with a StudentsToCourses collection.

Resources