Adding the results of two queries to ViewData.Model - asp.net-mvc

I have the following code in my controller:
public ActionResult Details(int id)
{
var dataContext = new BuffetSuppliersDBDataContext();
var supplier = (from m in dataContext.BO_Suppliers
where m.SupplierID == id
select m).FirstOrDefault();
ViewData.Model = supplier;
return View();
}
This renders a view which contains the properties returned from the linq to sql query. What I need to do now is add another query which will return x amount of ratings for each supplier, i will then loop through the records in the view and display the ratings.
How can I push the results of my ratings query into the view along with what is already there?

Your best option would to be create a class that you can pass into your view.
public class SupplierDetail
{
public Supplier { get; set; }
public SupplierRating { get; set; }
}
public class SupplierDetailViewData
{
public IEnumerable<SupplierDetail> SupplierDetails { get; set; }
}
Then in your controller action use a join and select a new SupplierDetail class in the LINQ query. After that you can create a strongly-typed view by using the code-behind and changing it to this...
public partial class Details : ViewPage<SupplierDetailViewData>
{
}
After that, in your view -- ViewData.Model will be SupplierDetailViewData. Of course the second part is optional but it does make for better compile-time validation.

Related

Using DBContext to Select Fields

I've got a couple questions regarding DBContext and achieveing my desired Results.
I can retrieve data like this
---Model
public class InvoiceModel
{
[Key]
public int? Invoice_Number { get; set; }
public decimal Amt_Total { get; set; }
public decimal Amt_Due { get; set; }
public decimal Amt_Paid { get; set; }
public List<InvoiceModel> GetInvoice()
{
using (VuittonEntities db = new VuittonEntities())
{
return (from inv in db.Invoice
select new InvoiceModel
{
Invoice_Number = inv.Invoice_,
Amt_Total = inv.AmountTotal,
Amt_Due = inv.AmountDue,
Amt_Paid = inv.AmountPaid
}).ToList();
}
}
--- Controller
public ViewResult Index()
{
var data = new InvoiceModel().GetInvoice();
return View(data);
}
This is pretty much standard LinQ and it returns my Invoice table with the 4 fields I selected. But now I want to achieve this using DB Context. So I added this new Class to my controller and called it in the view like this.
Controller
public class VuittonEntities : DbContext
{
public DbSet<InvoiceModel> Invoice { get; set; }
}
View
public ViewResult Index()
{
VuittonEntities db = new VuittonEntities();
return View(db.Invoice.ToList());
}
It returns the Entire table and I have to comment out my List'InvoiceModel' class
Assumptions:
VuittonEntities is my Connection String Name,
Invoice is the table
Vuitton is my .edmx class --
I heard that this can be achieved without having to use a Select Statement. It appears I am not linking my model class to a LinQ entity but when I add my context class, it throws errors on my inv."FieldName" columns in my List{InvoiceModel} Class.
TLDR Version:
How Can I return selected fields from DbContext Class instead of entire table
Why does adding a DBContext class raise errors on my List(ModelClass) fields
If you don't want the entire table, then don't just call ToList() on the DbSet, as that will just grab all of the table as you have seen.. You had it right when using Select, since the Select statement is meant to create a projection from one set of data into a new form (new class, model, anonymous object).

Entity framework how to pass data to view?

I am learning Entity Framework and MVC.
This is my model:
public class ChatLogContext : DbContext
{
public ChatLogContext()
: base("connString")
{
}
public DbSet<ChatLogs> ChatLogs { get; set; }
}
[Table("ChatLogs")]
public class ChatLogs
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ChatLogId { get; set; }
[Column("Message")]
public string Message { get; set; }
[Column("UserId")]
public int UserId { get; set; }
}
And this is my controller code here:
public ActionResult Index()
{
using(var db = new ChatLogContext())
{
var list = db.ChatLogs.Select(p => p.Message).SingleOrDefault();
ViewBag.data = list;
return View();
}
}
I then access that data in view like this:
#model Chat.Models.ChatLogs
#Html.Raw(ViewBag.data)
I can access 1 record as seen here with this.
But I would like to learn, how to access all records from the table ChatLogs with Entity Framework and pass it to view with Razor method(foreach), so I can format that data (I don't like default tables that VS generates). I am now using ViewBag for one row and 1 column, this is the most far I came.
I just can't find an examples on Google that would help my brains.
Help appreciated.
PS: Is it better to work with pure entity or mix linq(linq to entities)?
Typically the Index action is for showing a grid of all the entities (in this case ChatLogs).
One of the points of the Razor View Engine is that you get typed Views. So typically I would pass the data to the view directly as opposed to using the ViewBag.
public ActionResult Index()
{
using(var db = new ChatLogContext())
{
var list = db.ChatLogs.ToList();
return View(list);
}
}
The next step is to have the View typed to IEnumerable<ChatLog>. Visual Studio should help you with that. Then you can just foreach over the ChatLogs.

MVC - Multiple models in a view

I'm using MVC (for the first time) with Entity framework, Database first
What I want to do is display data from a database in a single view. I created the database first, then I made a ADO.NET Entity Data Model based from the database that contains all the tables. I then created a Index view that was strongly typed with my Entity Data Model as model.
In my Index I have at the top
#model IEnumerable<Forum6.Models.Forum>
This allows me to get the rows from the table "Forum" from my database. If I try to add an extra model I get I get this error message when I run:
Line 1: #model IEnumerable<Forum6.Models.Forum>
Line 2: #model2 IEnumerable<Forum6.Models.Post>
Parser Error Message: Only one 'model' statement is allowed in a file.
After searching for an answer I found this: Two models in one view in ASP MVC 3
The answer was to create a ViewModel (ParentModel) that contained all the Models (Tables).
This is the ViewModel I created:
public class ViewModel
{
public IEnumerable<Forum6.Models.Forum> Forum { get; set; }
public IEnumerable<Forum6.Models.Post> Post { get; set; }
public IEnumerable<Forum6.Models.Topics> Topics { get; set; }
public IEnumerable<Forum6.Models.Users> Users { get; set; }
public IEnumerable<Forum6.Models.PrivMsg> PrivMsg { get; set; }
public IEnumerable<Forum6.Models.Permission> Permission { get; set; }
}
I edited my controller to look like this:
public class HomeController : Controller
{
// ForumDBEntities old_db = new ForumDBEntities();
ViewModel db = new ViewModel();
public ActionResult Index()
{
return View(db);
}
}
Then replaced the old Index view with a new strongly typed view that used the ViewModel as model. Which contains:
#model IEnumerable<Forum6.Models.ViewModel>
Trying to run this gives me this error:
The model item passed into the dictionary is of type 'Forum6.Models.ViewModel', but this dictionary requires a model item
of type
'System.Collections.Generic.IEnumerable`1[Forum6.Models.ViewModel]
How do I make the "ViewModel" enumarable? Or is my error elsewhere?
You'll need to change #model IEnumerable<Forum6.Models.ViewModel> to #model Forum6.Models.ViewModel as you're wrapping your IEnumerables inside a single ViewModel.
A good rule of thumb is to have a 1:1 relationship between your ViewModel and View.
This might be a good read for you: http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/ (just ignore the automapper part if you don't want to go that route)
You'll also need to put in actual data in your ViewModel since
ViewModel db = new ViewModel();
public ActionResult Index()
{
return View(db);
}
will just give your view an empty ViewModel.
One way to do it would be.
public ActionResult Index()
{
var model = new ViewModel
{
Forum = db.GetForum(),
Post = db.GetPost(),
Topic = you get the idea
};
return View(model);
}
One last thing when naming properties or variables in general you should use the plural verb when it contains a list. So your ViewModel would be.
public class ViewModel
{
public IEnumerable<Forum6.Models.Forum> Forums { get; set; }
public IEnumerable<Forum6.Models.Post> Posts { get; set; }
public IEnumerable<Forum6.Models.Topics> Topics { get; set; }
public IEnumerable<Forum6.Models.Users> Users { get; set; }
public IEnumerable<Forum6.Models.PrivMsg> PrivMsgs { get; set; }
public IEnumerable<Forum6.Models.Permission> Permissions { get; set; }
}
Change #model IEnumerable<Forum6.Models.ViewModel> to #model Forum6.Models.ViewModel as you are passing a single instance of a ViewModel class and not a collection of them.
All your collections are passed in a single instance of a view model.

Accessing list properties in the typed view from a Viewmodel

I have a master view model, with the following two lists that are from two different DB tables,
public IEnumerable <Customer> SomeCustomer { get; set; }
public IEnumerable <CustomerSite> CustomerSites { get; set; }
In my controller I have
public ViewResult Index()
{
masterViewModel sitesModel = new masterViewModel();
return View(sitesModel);
}
Then in my view I write
#model IEnumerable<trsDatabase.Models.masterViewModel>
If I try to access the model by using a for each statement
#foreach (var customer in Model)
When I type #customer. It will only let me access the two lists not the individual properties in the list.
I thought I would have been able to do this with e.g.
#customer.CustomerSites.UnitNo
But the furthest i can go is
#customer.CustomerSites
And this obviously will not let me access the individual properties in the lists
Does anyone have any ideas on what I'm doing wrong here? Do I need to define the properties from the viewmodel in the controller? (I think not)
Update
I have the following code in my viewmodel,
namespace trsDatabase.Models
{
public class masterViewModel
{
public IEnumerable <Customer> Customers { get; set; }
public IEnumerable <CustomerSite> CustomerSites { get; set; }
}
}
Then the following in the controller,
public ViewResult Index()
{
masterViewModel sitesModel = new masterViewModel();
return View(sitesModel);
}
Then I changed my view declaration to
#model trsDatabase.Models.masterViewModel
This allows me to access the properties from the view perfectly, but it throws an error with the foreach loop as it can't be used when the view is inheriting the model rather than the Ienumerable list, do I need to change the syntax for rendering the list in the view and use something other than a foreachloop?
I think you need another loop, as CustomerSites is a collection:
#foreach (var customer in Model)
foreach (var site in customer.CustomerSites)
#site.UnitNo
EDIT AFTER COMMENT
Create a ViewModel class:
class ViewModel
{
public IEnumerable<Customer> Customer { get; set; }
}
Populate it in the controller and pass it to View() function.
Change the view to be typed (#model ViewModel).
Then inside view your Model property will be of type ViewModel and you can access customers collection through #Model.Customers

Populating Childnode list: Linq confusion and separation of concerns

I am trying to implement a tree view in my application. I am using MVC2 Preview 1, and SubSonic 3 SimpleRepository. I am new to both MVC and Linq.
My problem is that I am not sure how to add a list of child nodes to the model record that I am passing back to the View. So I have added a IEnumerable called Children to my model class that I populate in the controller action:
public class Category
{
public Category()
{
}
public int ID { get; set; }
public int? ParentId { get; set; }
[Required(ErrorMessage="Name is required")]
public string Name { get; set; }
[SubSonicIgnore]
public IEnumerable<Category> Children { get; set; }
}
Then in the controller action, I pull all of the records and iterate through updating the Children member:
public ActionResult Index()
{
var categories = _repo.All<Category>();
foreach (var c in categories)
{
c.Children = from p in _repo.All<Category>()
where p.ParentId == c.ID
orderby p.Name
select p;
}
return View(categories);
}
My 2 questions are #1 Why does this not work? Outside of the scope of the loop my changes are lost. #2 In a general sense, is this the right approach? Putting this code in the controller feels like a hack.
As for why it doesn't work, I suspect deferred execution is getting you. If you wrap the Linq query like so( from ... select p).ToList() it will cause the query to be evaluated.
Regarding the approach, it is data access in the presentation tier, so generally speaking, that would be something to avoid.

Resources