I'm trying to list the items from my database into my view but I'm getting null back.
I know the connection must be working to a certain extent because in my database the tables didn't exist but once I ran my program it did create the tables. However when I add content into my table my view still returns NULL.
Also, haven't touched the Review table yet, just worried about getting Restaurants working.
Restaurant.cs
namespace OdeToFood.Models
{
public class Restaurant
{
public int Id { get; set; }
public string Name { get; set; }
public string City { get; set; }
public string Country { get; set; }
public ICollection<RestaurantReview> Reviews { get; set; }
}
}
OdeToFood.cs
namespace OdeToFood.Models
{
public class OdeToFoodDb : DbContext
{
public DbSet<Restaurant> Restaurants { get; set; }
public DbSet<RestaurantReview> Reviews { get; set; }
}
}
Controller
OdeToFoodDb _db = new OdeToFoodDb();
public ActionResult Index()
{
var model = _db.Restaurants.ToList();
return View();
}
Index.cshtml
#model IEnumerable<OdeToFood.Models.Restaurant>
#{
ViewBag.Title = "Home Page";
}
#{
if (Model != null)
{
foreach (var item in Model)
{
<div>
<h4>#item.Name</h4>
<div>#item.City, #item.Country</div>
<hr />
</div>
}
}
else
{
<h1>Null</h1>
}
}
You need to pass to model back to the view.
OdeToFoodDb _db = new OdeToFoodDb();
public ActionResult Index()
{
var model = _db.Restaurants.ToList();
return View(model);
}
You never actually send the model to the view. Pass it as an argument:
OdeToFoodDb _db = new OdeToFoodDb();
public ActionResult Index()
{
var model = _db.Restaurants.ToList();
return View(model);
}
Additionally, it's generally a good idea not to create database contexts in a shared scope. Keep the context as close to where it's used as possible and only expand its scope when you really need to. Something like this:
public ActionResult Index()
{
using (var _db = new OdeToFoodDb())
{
var model = _db.Restaurants.ToList();
return View(model);
}
}
Database contexts/connections in a shared scope is just asking for problems unless you pay close attention to what you're doing. As the code gets more complex, it becomes more likely that other methods will try to use it and it may be in an unknown state at that time.
Related
I don't have much experience with programming and I'm new to MVC.
I want to fetch some data from database with entity framework and print it in the view.
This is my model:
public class Grad
{
public int ID { get; set; }
public string Naziv { get; set; }
public char KoordinataX { get; set; }
public char KoordinataY { get; set; }
public int BrojStanovnika { get; set; }
}
public class GradDBContext : DbContext
{
public DbSet<Grad> Gradovi { get; set; }
}
this is a controller:
private GradDBContext db = new GradDBContext();
public ActionResult Index()
{
List<int> gradoviList = new List<int>();
foreach (sea.Models.Grad g in db.Gradovi)
{
gradoviList.Add(g.ID);
}
ViewData["Gradovi"] = new SelectList(gradoviList);
return View();
}
and this is a view:
#foreach (var item in ViewData["Gradovi"] as IEnumerable<int>) ---> error appears here as null reference exception
{
<p>item</p>
}
I know that I have to parse data but don't have idea what did I do wrong
The ViewData item with the key "Gradovi" is typeof SelectList, so it would need to be
#foreach (var item in ViewData["Gradovi"] as SelectList)
{
<p>#item.Value</p> // or #item.Text
However there is no point generating IEnumerable<SelectListItem> (which is what SelectList is) when you do not need it, and you should be passing your model to the view. Your code in the controller should be
public ActionResult Index()
{
IEnumerable<int> model = db.Gradovi.Select(x => x.ID);
return View(model);
}
and in the view
#model IEnumerable<int>
#foreach(var item in Model)
{
<p>#item</p>
}
Your code can work like you have it, but I am going to modify it a bit and give you some pointers. I am supplying an answer based on what I see in your post, not what I think you want to achieve at a later stage. There are many ways to accomplish a goal, I will select the simplest way that I will normally use:
public ActionResult Index()
{
// You will have a repository layer for this part
GradDBContext db = new GradDBContext();
// Get a list of your items
List<Grad> gradovis = db.Gradovi.ToList();
// I never work with view data, I just pass my view model to the view
// This way you now have more data to display on the screen (if you need more)
return View(gradovis);
}
And then your view could look like this:
#model List<Project.Model.Grad>
#foreach (var grad in Model)
{
<p>#grad.ID</p>
}
I am trying to add a create controller method for a child table of application user. I can't figure out how to populate the user id. I'm in the process of learning mvc and this seems like such a basic concept, but I can't get it to work. Here is my class.
public class Ticket
{
[Key]
public long Id { get; set; }
[StringLength(128), MinLength(3)]
[ForeignKey("AspNetUser")]
public virtual string AspNetUserId { get; set; }
public virtual ApplicationUser AspNetUser { get; set; }
public DateTime Date { get; set; }
public string Request { get; set; }
}
Here is my index - hopefully pulling only records associated to the current user. I don't have seed data setup, so I have to get create working in order to test this, but the view comes up.
public ActionResult Index()
{
//var userId = User.Identity.GetUserId();
var userId = UserManager.FindById(User.Identity.GetUserId());
var tickets = db.Tickets.Where(m => m.AspNetUser == userId); ;
return View(tickets.ToList());
}
My create get which also comes up, but doesn't seem to be linked up.
public ActionResult Create()
{
return View();
}
And here is my troublesome create post method. When I click submit nothing happens.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Id,AspNetUserId,Date,Request")] Ticket ticket)
{
if (ModelState.IsValid)
{
ticket.AspNetUserId = User.Identity.GetUserId();
db.Tickets.Add(ticket);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(ticket);
}
Within my view I have a #Html.HiddenFor(model => model.Id) for the Id, but since it's not posting I assume my ModelState is not valid.
So frustrating.
I have an entity that I am updating and the method in the controller has these lines in it;
db.Entry(userdetails).State = EntityState.Modified;
try {
db.SaveChanges();
}
I think this is fine, however the entity has a collection in it and these records needs to be created, not updated. I am therefore getting this error;
"Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries."
I have read that this may be because my AppUserInfo objects have an id of 0 because they need to be added.
The class for the outer entity looks like this;
public class User {
public Guid UserId { get; set; }
public string PhoneNumber { get; set; }
public string Email { get; set; }
public List<AppUserInfo> InfoList { get; set; }
}
Now in this situation for example, the phone number could have been modified, and the 'InfoList' collection has new items in that need to be created. Some may need to be updated as well. The 'AppUserInfo' class looks like this;
public class AppUserInfo
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int AppUserInfoId { get; set; }
public string info { get; set; }
}
How do I handle this in EF? Am I allowed to save collections in this way? I do not know how to say that there are modifications and additions and possible deletions in the list to EF. Do I simply just remove the line;
db.Entry(userdetails).State = EntityState.Modified;
Any info on the correct way to do this would be very helpful.
Thanks,
db.Entry(userdetails).State = EntityState.Modified;
This line of code is used for editing your objects, if you have no trouble creating your User then all you need is another controller to handle AppUserInfo
Lets imagine that you have a AppUserInfo controller, and you have a AppUserInfo viewModel somewhere. Then you can somthing like the following to accomplish what you want to do.
Your view model like this:
puclic class AppUserInfoCreateViewModels
{
public Guid UserId { get; set; }
public string Info { get; set; }
}
Then your Controller like this:
public class AppUserInfoController : Controller
{
private readonly IYourDataSource _db;
public AppUserInfoController(IYourDataSource db)
{
_db = db;
}
[HttpGet]
public ActionResult Create(int userId)
{
var model = new AppUserInfoCreateViewModels();
model.UserId = userId;
return View(model);
}
[HttpPost]
public ActionResult Create(AppUserInfoCreateViewModels viewModel)
{
if(ModelState.IsValid)
{
var user = _db.Users.Single(d => d.UserId == viewModel.UserId);
var appUserInfo= new AppUserInfo();
appUserInfo.Info= viewModel.Infor;
user.AppUserInfos.Add(appUserInfo);
_db.Save();
return RedirectToAction("detail", "user", new {id = viewModel.UserId});
}
return View(viewModel);
}
}
I hope this helps, ask any questions you may have
I have an index page that lists all users. This has the following in the Users controller -
public ViewResult Index()
{
return View(userRepository.AllIncluding(user => user.Roles));
}
and then the view starts with
#model IEnumerable<TRS.Models.User>
and then uses
#foreach (var item in Model) {
to loop through all users in my model.
I now need to change my model to a ViewModel that contains both the User model and an extended UserDetails model.
I have changed my Index view to use the view model -
#model IEnumerable<TRS.ViewModels.RegisterViewModel>
But I don't know how I should be going about filling the ViewModel in my controller -
public ViewResult Index()
{
var viewModel = new RegisterViewModel
{
UserName = "???"
FirstName = "???"
LastName = "???"
};
return View(viewModel);
}
I assume I need to create an instance of the view model and then pass it to the view. But I don't understand how I can get data against each individual item. I'll obviously need to get all data for all users here and then loop through them in my view. Any ideas what I should be going in the controller above? What should replace the "???" with that will fill the viewModel with all the data? Or is this the wrong approach?
Thanks
Edit - Models added -
public class User
{
[Key]
public string UserName { get; set; }
public virtual ICollection<Role> Roles { get; set; }
public virtual UserDetails UserDetails { get; set; }
}
public class UserDetails
{
[Key]
public string UserName { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
[Required]
public virtual User User { get; set; }
}
Edit - From View -
<td>
#foreach (Role role in item.Roles){
#role.RoleName <br />
}</td>
public ActionResult Index()
{
var usersVm = userRepository
.AllIncluding(user => user.Roles)
.Select(user => new RegisterViewModel
{
UserName = user.UserName
FirstName = user.UserDetails.FirstName
LastName = user.UserDetails.LastName
});
return View(usersVm);
}
Automapper was created for this very thing. I'd highly recommend it.
Take a read of getting started section of wiki.
Once you have it configured your controller code would look something like this:
List<RegisterViewModel> registrants =
Mapper.Map<List<User>, List<RegisterViewModel>>(users);
Though you might want to consider a viewmodel that has a list of registrants on them but that is up to you.
Your viewModel
Public Class RegisterViewModel
{
Public IEnumerable<TRS.Models.User> AllUsers {get;set;}
Public IEnumerable<TRS.Models.UserDetails> UserDetails {get;set;}
}
Then in your controller
public ViewResult Index()
{
var viewModel = new RegisterViewModel
{
AllUsers = userRepository.AllIncluding(user => user.Roles).ToList()
};
var DetailList = new list<TRS.Models.UserDetails>();
foreach(var user in viewModel.AllUsers)
{
DetailList.add(new userDetails
{
name = user.Name,
age = user.age,
....
}
}
viewModel.UserDetails = DetailList;
return View(viewModel);
}
it is unclear from your question what UserDetails look like.
You should not use IEnumerable<RegisterViewModel> in your view. The RegisterViewModel should be the container of everything you will need in the view:
public ViewResult Index()
{
var usersDetails = GetUserDetails(userRepository.AllIncluding(user => user.Roles));
var viewModel = new RegisterViewModel
{
UserDetails = usersDetails.ToList(),
SomeMoreDataRequiredByTheView= "1"
};
return View(viewModel);
}
//you can use automapper to do this dirty job.
private IEnumerable<UserDetails> GetUserDetails(IEnumerable<User> users)
{
foreach(var user in users)
{
yield return new UserDetails()
{
FullName = user.FirstName + " " + user.LastName,
// Other stuff you want
};
}
}
I am trying to pass a stored procedure mapped to a method called ListLeagueLeaders() but the autogenerated method to invoke a stored procedure, ObjectResult<ListLeagueLeaders_Result> ListLeagueLeaders() is expecting an ObjectResult type. What can I do to fix this?
I thought of using LINQ instead of a stored procedure, but I want to give this tactic a last chance. Related: LINQ to Entities instead of stored procedure?
HomeController
public class HomeController : Controller
{
HockeyStatsEntities db = new HockeyStatsEntities();
public ActionResult Index()
{
ViewBag.Message = "League leaders";
{
return View(db.ListLeagueLeaders());
}
}
private ICollection<ListLeagueLeaders_Result> ListLeagueLeaders()
{
ICollection<ListLeagueLeaders_Result> leagueLeadersCollection = null;
using (HockeyStatsEntities context = new HockeyStatsEntities())
{
foreach (ListLeagueLeaders_Result leagueLeader in
context.ListLeagueLeaders())
{
leagueLeadersCollection.Add(leagueLeader);
}
}
return leagueLeadersCollection;
}
}
Model1.Context.cs
public partial class HockeyStatsEntities : DbContext
{
public DbSet<Dim_Date> Dim_Date { get; set; }
public DbSet<Dim_Player> Dim_Player { get; set; }
public DbSet<Dim_Team> Dim_Team { get; set; }
public DbSet<Fact_Statistics> Fact_Statistics { get; set; }
public DbSet<Dim_Game> Dim_Game { get; set; }
public virtual ObjectResult<ListLeagueLeaders_Result> ListLeagueLeaders()
{
((IObjectContextAdapter)this).ObjectContext.MetadataWorkspace.LoadFromAssembly(typeof(ListLeagueLeaders_Result).Assembly);
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<ListLeagueLeaders_Result>("ListLeagueLeaders");
}
}
View:
#model NHLStats2.Models.ListLeagueLeaders_Result
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
You are getting this error on your View. You need to reference the same object type which you are retuning from your controller action.
For example, if you are returning type of List<Foo> from your controller action, you can only make your view strongly typed to List<Foo> or IList<Foo> or IEnumerable<Foo> and etc.