Running this Index controller gives me errors, when I try to pass IEnumerable into Tempdata.
When debugging, TempData["ProductCategory"] seems to store expected data in Watch, but cannot render Html View after storing. However, the Html does show when I store a simple stirng.
public IActionResult Index()
{
// This gives me http error 500
//TempData["ProductCategory"] = productcategoryrepository.GetAllProductCategory();
// This works at least!
TempData["ProductCategory"] = "test";
//TempData.Keep();
return View();
}
public IEnumerable<ProductCategory> GetAllProductCategory()
{
return _context.ProductCategory.ToList();
}
Other Info:
public partial class ProductCategory
{
public ProductCategory()
{
Product = new HashSet<Product>();
}
public int ProductCategoryId { get; set; }
public string ProductCategoryName { get; set; }
public string ProductCategoryDescription { get; set; }
public virtual ICollection<Product> Product { get; set; }
}
public partial class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public string ProductDescription { get; set; }
public string ImageLocation { get; set; }
public int? ProductCategoryId { get; set; }
public virtual ProductCategory ProductCategory { get; set; }
}
To be able to store data in sessions or temp data, the type must be serializable. IEnumerable<T> cannot be serialized. Try a List<T> instead.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/app-state?view=aspnetcore-2.1
Sql Tables Here
public partial class Users
{
public Users()
{
UsersRelationFollower = new HashSet<UsersRelation>();
UsersRelationFollowing = new HashSet<UsersRelation>();
Vote = new HashSet<Vote>();
VoteRating = new HashSet<VoteRating>();
}
public string Id { get; set; }
public string UserType { get; set; }
public string UserName { get; set; }
public string Mail { get; set; }
public string ImageUrl { get; set; }
public DateTime CreationDate { get; set; }
public DateTime? ModifyDate { get; set; }
public bool State { get; set; }
public virtual UserPasswords UserPasswords { get; set; }
public virtual CorporateProperty CorporateProperty { get; set; }
public virtual UserProperty UserProperty { get; set; }
public virtual ICollection<UsersRelation> UsersRelationFollower { get; set; }
public virtual ICollection<UsersRelation> UsersRelationFollowing { get; set; }
public virtual ICollection<Vote> Vote { get; set; }
public virtual ICollection<VoteRating> VoteRating { get; set; }
}
public partial class UserProperty
{
public string Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public DateTime BirthDay { get; set; }
public string Gender { get; set; }
public string Locale { get; set; }
public string PhoneNumber { get; set; }
public bool State { get; set; }
public virtual Users IdNavigation { get; set; }
}
public partial class CorporateProperty
{
public string Id { get; set; }
public string OrganisationName { get; set; }
public string Website { get; set; }
public bool State { get; set; }
public virtual Users IdNavigation { get; set; }
}
UserControllerClass
// GET: api/Users/5
[HttpGet("{id}")]
public async Task<IActionResult> GetUsers([FromRoute] string id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var users = await _context.Users.SingleOrDefaultAsync(m => m.Id == id);
if (users == null)
{
return NotFound();
}
return Ok(users);
}
My problem is exactly this; User information is coming but the password and property table information is not coming.
How to modify the following line solves my problem?
var users = await _context.Users.SingleOrDefaultAsync(m => m.Id == id);
based on your code this would also hydrate your CorporateProperty & UseProperty objects, etc.
var user = await _context.Users.Include(user => user.UserProperty).Include
(user => user.CorporateProperty).SingleOrDefaultAsync(user => user.Id == id);
lazy loading doesn't exist yet so you have Eager Loading to play with for now.
Surprised you didn't roll with Identity since this all of this would have been taken care for you especially Passwords... Hope you aren't rolling your own hash for that..
Just add in the custom class / collection objects you need.
you can also check out this link
https://learn.microsoft.com/en-us/ef/core/querying/related-data
I have been trying to make this happen for a few hours now.I have two models within my model folder called Models, i am trying to pull data from the model to display it in the view, i am aware of only one model statement can be applied to the view. So i have Created a ViewModels which contain the properties that i would like to reference in the view. now when i run the the application im getting a compilation Error which says:
"Compiler Error Message: CS0246: The type or namespace name 'Models' could not be found (are you missing a using directive or an assembly reference?)"
I would appreciate a bit of help of if there is any other way of doing it feel free to advice.
New ViewModel created
public class MainModelscs <T> where T :class
{
public StoreAudit StoreAudit { get; set; }
public StoreQuestions StoreQuestions { get; set; }
public List<string> StoreWindow { get; set; }
public IPagedList<T> IndexList { get; set; }
}
ViewMode PROPERTIES inside my view,
#model PopMarketing.ViewModel.MainModelscs<PopMarketing.Models>
Model 1
public class StoreQuestions
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int ReviewId { get; set; }
public int AuditId { get; set; }
public int QuestionOne { get; set; }
public string QuestionTwo { get; set; }
public string QuestionThree { get; set; }
public string QuestionFour { get; set; }
}
Model 2
[Key]
[Column(Order = 1)]
public int AuditId { get; set; }
public string Date { get; set; }
public int StoreNumber { get; set; }
public string StoreName { get; set; }
public string Address { get; set; }
public string Manager { get; set; }
Controller Method
public class AuditController : Controller
{
private PopMarketingContext db = new PopMarketingContext();
//
// GET: /Audit/
private const string PASSWORD = "MarchJava2016";
public ActionResult Index(string searchString)
{
int number;
int check;
bool result = Int32.TryParse(searchString, out number);
if (result)
{
check = Convert.ToInt32(searchString);
var shops = from s in db.StoreAudit
select s;
if (!String.IsNullOrEmpty(searchString))
{
shops = shops.Where(s => s.StoreName.ToUpper().Contains(searchString.ToUpper()) ||
s.StoreNumber.Equals(check));
}
return View(shops.ToList());
}
else
{
var shops = from s in db.StoreAudit
select s;
if (!String.IsNullOrEmpty(searchString))
{
shops = shops.Where(s => s.StoreName.ToUpper().Contains(searchString.ToUpper()));
}
return View(shops.ToList());
}
}
Jaimin is correct, in #model you pass the class you want to use as model, not the directory or namespace of the class.
As for using viewmodels correctly:
Let's say I have two classes:
class Student
{
public string name;
public string mentor;
}
class Teacher
{
public string name;
public string salary;
}
And i want to have a view show both their names. I can create a viewmodel like this:
class StudentAndTeacherVM
{
public Teacher teacher;
public Student student;
}
The controller would look like this:
public ActionResult Index()
{
var student = new Student();
*fill student*
var teacher = new Teacher();
*fill teacher*
var model = new PersonVM();
model.teacher = teacher;
model.student = student;
return view(model);
}
Now you can reach them in the view by:
#Model.student.name
#Model.teacher.name
Or if I want to be as efficient as possible, I could also just put in the names into the VM.
controller:
public ActionResult Index()
{
var student = new Student();
*fill student*
var teacher = new Teacher();
*fill teacher*
var model = new PersonVM();
model.teacherName = teacher.name;
model.studentName= student.name;
return view(model);
}
View:
class StudentAndTeacherVM
{
public string teacherName;
public string studentName;
}
Create instance of MainModelscs in your action
. . .
i.e. MainModelscs <string> Obj = new MainModelscs <string> ;
. . .
Then pass this to the view.
return View(Obj);
Now in your view,
#model PopMarketing.ViewModel.MainModelscs<string>
(take T as your model name not the namespace!)
Sorry, i got much late than i said. But here is how you can join two tables, map them to a model and pass to the view. The first one of the class whose properties correspond to the comments table of the database.
public class Comments
{
public int ID { get; set; }
public string CommentText { get; set; }
public string Username { get; set; }
public int Upvote { get; set; }
public int Downvote { get; set; }
public int InappropriateFlags { get; set; }
public int PostId { get; set; }
public string ControllerName { get; set; }
public int ReplyTo { get; set; }
public bool replied { get; set; }
}
Now another user profiles table which is needed to be joined with the comments table.
public class UserProfile
{
public int ID { get; set; }
public string Username { get; set; }
public string DisplayName { get; set; }
public int Reputation { get; set; }
public DateTime DateOfRegistration { get; set; }
public int Money { get; set; }
public string ImageUrl { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Country { get; set; }
public string State { get; set; }
public string City { get; set; }
public string Location { get; set; }
public int? PostalCode { get; set; }
public int ProfileViews { get; set; }
public string AboutMe { get; set; }
}
Now the much needed model for handling the join of these two tables. I haven't included all the properties of both tables as i didn't need them in the view, but you can ofcourse include them. In that case, don't forget to update your data access query also.
public class CommentUserProfileJoin
{
public int ID { get; set; }
public string CommentText { get; set; }
public string Username { get; set; }
public string DisplayName { get; set; }
public int Upvote { get; set; }
public int Downvote { get; set; }
public int InappropriateFlags { get; set; }
public int PostId { get; set; }
public string ControllerName { get; set; }
public int ReplyTo { get; set; }
public bool replied { get; set; }
public int UserProfileId { get; set; }
}
I am using dapper ORM. So this is the data access code that creates a join and maps it to the join table written above.
public IEnumerable<CommentUserProfileJoin > GetComments(int postId, string controllerName, int replyTo)
{
IEnumerable<CommentUserProfileJoin> comments;
const string query = "Select c.[id], c.[CommentText], c.[Username], c.[Upvote], c.[Downvote], c.[InappropriateFlags], c.[PostId], c.[ControllerName], c.[ReplyTo], c.[replied], u.[id] as UserProfileId, u.displayname from Main.Comments c LEFT JOIN Profile.UserProfiles u on c.username = u.username where c.PostId = #postId and c.ControllerName = #contName and c.ReplyTo = #ReplyTo order by ID desc";
comments = conObj.Query<CommentUserProfileJoin>(query, new { postId = postId, contName = controllerName, ReplyTo = replyTo });
return comments;
}
so now i have the model for the join of two tables, i can use it in any view like this
#model IEnumerable<DataAccessLayer.Models.CommentUserProfileJoin>
Hope this helps you. Also, unintentionally, i may not have followed best practices. I will be glad if someone can notify them through comments. Thanks
still pretty new to ASP.NET. I have two models, and two API controllers. I was hoping I could create all the methods for both controllers in my EFRepository, but it seems to only let me use objects from the first model I built. My question is, do I just create another repository for the second model/API? Or is it best practice to create a generic and use server-side services for my methods? Or is there something else I am missing in my thought process? Thanks!
Record Model
namespace Train.Models {
public class Record {
public int Id { get; set; }
public int Quantity { get; set; }
public DateTime DateCreated { get; set; }
public bool IsActive { get; set; }
public ApplicationUser User { get; set; }
public virtual ICollection<Cars> Cars { get; set; }
}
}
Cars Model
namespace Train.Models {
public class Cars {
public int Id { get; set; }
public string EmptyOrLoaded { get; set; }
public string CarType { get; set; }
//Hopper, flatbed, tank, gondola, etc.
public string ShippedBy { get; set; }
//UP(Union Pacific) or BNSF
public string RailcarNumber { get; set; }
//public virtual ApplicationUser ApplicationUser { get; set; }
public string UserId { get; set; }
public string RecordId { get; set; }
public virtual Record Record { get; set; }
}
}
API CarsController Method
public IHttpActionResult Post(Cars car) {
car.UserId = User.Identity.GetUserId();
if (!ModelState.IsValid) {
return BadRequest(this.ModelState);
}
_repo.SaveCar(car);
return Created("", car);
}
API Recordcontroler Method
public IHttpActionResult PostRecord(Record record) {
var UserId = this.User.Identity.GetUserId();
if (!ModelState.IsValid) {
return BadRequest(this.ModelState);
}
_repo.SaveRecord(record);
return Created("", record);
}
Save Car Method in EFRepository
public void SaveCar(Cars carToSave) {
if (carToSave.Id == 0) {
_db.Cars.Add(carToSave);
_db.SaveChanges();
} else {
var original = this.Find(carToSave.Id);
original.EmptyOrLoaded = carToSave.EmptyOrLoaded;
original.CarType = carToSave.CarType;
original.ShippedBy = carToSave.ShippedBy;
original.RailcarNumber = carToSave.RailcarNumber;
_db.SaveChanges();
}
this is how the controller looks like
public ActionResult Edit()
{
return View();
}
[HttpPost]
public ActionResult Edit(Car _car)
{
if (ModelState.IsValid)
{
entities.Entry(_car).State = EntityState.Modified;
entities.SaveChanges();
RedirectToAction("Stock");
}
return View(_car);
}
the page itself is pretty much the "Edit" template with just a different redirect at the bottom.
this is the Car class
public partial class Car
{
public Car()
{
this.Orders = new HashSet<Order>();
}
public int CarID { get; set; }
public string Manufacturer { get; set; }
public string Model { get; set; }
public decimal Daily_Cost { get; set; }
public decimal Late_Fee { get; set; }
public int Year { get; set; }
public string Gear { get; set; }
public int Mileage { get; set; }
public bool Available { get; set; }
public string Registration { get; set; }
public int Location { get; set; }
public string Picture { get; set; }
public virtual Branch Branch { get; set; }
public virtual ICollection<Order> Orders { get; set; }
}
I'm not exactly sure what's causing the ModelState to be invalid but when I look at the object at runtime the only thing I see that I think is wrong, is Branch is null.
Branch is in a relationship in the db with Location. Location is foreign key and Branch is primary key (in the DB it's BranchID but I don't think that's relevant)