I'm trying to bind columns from two different tables in to gridview using Linq To Sql
Here's the bind:
var q = (from o in mail.tblmails
join c in mail.tblstaffs on o.staffId equals c.id
select new { o, c });
return View(q);
and here is where I'm calling the bind in my View.
.Columns(columns =>
{
columns.Bound(o => o.dateAdded).Format("{0:MM/dd/yyyy}").Width(80);
columns.Bound(o => o.companyId);
//columns.Bound(c => c.staffId);
columns.Bound(o => o.subject);
columns.Bound(o => o.dateArchived);
})
I'm getting an error
Exception Details: System.InvalidOperationException: The model item passed into the dictionary is of type 'System.Data.Linq.DataQuery1[<>f__AnonymousType06[System.Nullable1[System.DateTime],System.Nullable1[System.Int32],System.String,System.Nullable1[System.DateTime],System.String,System.Int32]]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1[ffs.Models.tblmail]'.
I have a feeling that the issue may have something to do with the line
< % Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage>"%>
but I'm not sure what to do to fix it.
I'm using the telerik grid extension.
Any help would be great, thanks.
What you are doing now (and doing wrong also) is sending the query data directly to the view. This is considered bad practice. Although possible to acces the resulting anonymous type, this method will cause to do your data acces during the view instead of in the controller.
What I recommend is you make a model (class) to represent the data and return a list of those entities (your model) to the view using:
<% Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<List<yourCreatedModelClass>>"%>
Watch the part where you tell the view you are handing it a list of your objects rather than just a clean view.
Some related problem and solution is discussed here
I think the problem (looking at your error message) lies in the fact that you are trying to pass an anonymous type around while the view is expecting an IEnumerable<tblmail>.
What you want to do is create a data structure like:
public class Model
{
public tblmails Mails { get; set; }
public tblstaff Staff { get; set; }
}
Then in your linq query you would put o into Model.Mails, and then put c into Model.Staff. You then pass your IEnumerable<Model> result into your view, and hook your view up so it is expecting IEnumerable<Model> as the model.
Related
Somewhere I had to use a linq statement for select a result set from my Model that Controller returned in Index ActionResult.
for doing this, I googled "how to use linq in view razor" and I get the result and my application worked properly, but I see some recommendation that say "Don't use Linq in view".
Why we shouldn't use it however it's possible?
And if I don't want using it what's the solution?
This is my query :
#using System.Linq
#{var lst = (from x in item.Showtimes select x.ShowtimeDate).Distinct();}
#foreach (var showTimeItem in lst)
{
<option value="#showTimeItem">#showTimeItem</option>
}
UPDATE
This is my controller Index
public ActionResult Index()
{
MelliConcert.Models.MelliConcertEntities db = new Models.MelliConcertEntities();
var listOfConcerts = (from x in db.Concert
orderby x.ID ascending
select x).Take(15).ToList();
return View(listOfConcerts);
}
And i use it in the view like this :
#model IEnumerable<MelliConcert.Models.Concert>
#foreach (var item in Model)
{
#if (item.OpenedForFirst == true)
{
//...
}
//Some Codes
#using System.Linq
#{var lst = (from x in item.Showtimes select x.ShowtimeDate).Distinct();}
#foreach (var showTimeItem in lst)
{
<option value="#showTimeItem">#showTimeItem</option>
}
}
My linq statement placed in this loop.
What should i do?
There's nothing inherently wrong with using LINQ in a view per se. The problem isn't that you're using LINQ, the problem is that you're doing this:
#{var lst = (from x in item.Showtimes select x.ShowtimeDate).Distinct();}
Any time you have to declare and set a variable inside your view, that's probably an indication that you need to modify your model. Your view model should have a property on it for this purpose. Something like this:
public IEnumerable<SomeType> DistinctShowtimes
{
get
{
return (from x in item.Showtimes select x.ShowtimeDate).Distinct();
}
}
Then the point about LINQ in the view becomes moot, as all you'd need is this:
#foreach (var showTimeItem in Model.DistinctShowtimes)
{
<option value="#showTimeItem">#showTimeItem</option>
}
UPDATE (in response to your updated question):
Now the problem (albeit slightly less of one) is this:
#model IEnumerable<MelliConcert.Models.Concert>
While this works fine, it's limiting. And what you're experiencing is that limitation. You're asking yourself, "How do I return more than one thing to the view?" The answer is to create a custom view model for that view. Right now your view is binding to an enumeration of Concert objects. Which is fine, if that's all it needs. But it turns out that's not all it needs. It has some custom logic that requires a little more. So, you create a custom view model. Something like this:
public class ConcertsViewModel
{
public IEnumerable<Concert> Concerts { get; set; }
// other properties, methods, anything
}
Then in your controller action, you return one of those instead:
public ActionResult Index()
{
using(var db = new Models.MelliConcertEntities())
{
var concertsModel = new ConcertsModel();
concertsModel.Concerts = (from x in db.Concert
orderby x.ID ascending
select x).Take(15).ToList();
return View(concertsModel);
}
}
(Note also the use of the using statement, which should always be employed when making use of IDisposable resources.)
So now your view is still getting the list of Concert objects, but it's packaged in a custom view model onto which you can add any more functionality you need for that view. Next, in your view, change the model declaration:
#model MelliConcert.Models.ConcertsViewModel
(This assumes you put it in the Models namespace. Depending on the scale of your application, you might want to break out view models into their own namespace. I don't often use the Models namespace in the actual application for core business objects, so our projects are likely structured very differently. This should get you going, but you'll want to make sure you keep your concerns cleanly separated.)
Then in the view code you can reference what you need from that object. So if you need to access the list, instead of just calling something like #foreach (var item in model) you would call #foreach (var item in model.Concerts).
I think in this case the argument would be to do the maximum amount of processing on your model before returning it to the view.
So why not return distinct showtimes to the view and then just loop through them?
The only problem with your current set up is it may undermine the spirit of MVC which was to separate concerns. The view shouldn't be applying any logic that needs to be tested (or as little as possible). By keeping logic in the models and controllers you make unit testing easier and the views are simpler for a developer to read.
EDIT
Hey #samangholami, you can return multiple objects to a view using a class. Create a class called "PAGENAMEViewModel" or something similar and create a property for every value you want to return. For example:
public class MovieViewModel
{
public string MovieName { get; set; }
public IEnumerable<string> Actors { get; set; }
public IEnumerable<ShowTimeRecord> Showtimes { get; set; }
public class ShowTimeRecord
{
public string TheaterName { get; set; }
public string TheaterAddress { get; set; }
public DateTime ShowtimeDate{ get; set; }
}
}
Then return your complex model like so:
public ActionResult Index()
{
MovieViewModel model = myMovieHelper.GetMovieData();
return View(model);
}
Besides the possible separation of concerns problem you also might have a performance problem that can be more difficult to diagnose.
If your LINQ query is somehow connected to the database via some ORM or something like that by looping through the results you might create a N+1 problematic scenario.
Moving it off the view might not prevent it, but at least puts it into somewhere that is more visible.
I believe that's because it's not respecting the separation of concerns principle, which is a fundamental concept of MVC. By performing that query in the view, you're taking business logic to it.
It has nothing to do with Linq itself. You could, for example, have a Linq statement to perform an OrderBy. That's ok because it's not business logic, it's a proper view operation (to order data into a table, let's say).
My domain object Store holds a reference to the object Chain:
public class Store
{
public Chain Chain { get; set; }
}
On creating a new store there is the possibility to set the associated chain. I am realising this by passing the chain objects via ViewBag and use the Html.DropDownListFor for selection:
#Html.DropDownListFor(
x => x.Chain,
new SelectList(ViewBag.Chains, "Id", "Name"))
So far so good, but back in the controller (after submitting) the chain property is null. I figured that I can set the DropDownList to Chain.Id but then I need to load the entity again. Is there a better way to get/keep the correct reference?
Is there a better way to get/keep the correct reference?
No, that's how HTML works. Only the selected value is sent to the server and you need to use this value to load the corresponding entity. Please learn HTML before getting into ASP.NET MVC development. It would help you very much. That's the correct way:
#Html.DropDownListFor(
x => x.Chain.Id,
new SelectList(ViewBag.Chains, "Id", "Name")
)
Well, as a matter of a real fact, to be totally honest with you the most correct way to handle this is to get rid of all ViewBag crap and use a real view model in your application:
#Html.DropDownListFor(
x => x.ChainId,
Model.AvailableChains
)
where AvailableChains will of course be a property of type IEnumerable<SelectListItem> on the view model you prepared for this view. You should always be using a view model and never be passing your domain models to your view if you want to be doing ASP.NET MVC the right way.
And here's how your view model might look like:
public class MyViewModel
{
public int ChainId { get; set; }
public IEnumerable<SelectListItem> AvailableChains { get; set; }
}
Maybe this is very simple to do but I can't find the good words when I search on stackoverflow or on google.
I have a model and this model contains a "Country" property that is a integer. When I am in the Edit view, this property is used this way and it work well.
#Html.DropDownListFor(model => model.Country, new SelectList(ViewBag.Countries, "IDCountry", "Name"))
In the Details view, I only want to show the name of the country, but I don't know how! Right now, I'm doing this but it only show the ID and I can't find a way to give him the List so it use it as a datasource or something like that to show "Canada" instead of 42.
#Html.DisplayFor(model => model.Country)
How can this be achieved?
How can this be achieved?
By using a view model of course:
public class CountryViewModel
{
public int CountryId { get; set; }
public string CountryName { get; set; }
}
and then you would populate this view model in the controller action that is supposed to render your Display view:
public ActionResult Display(int id)
{
Country country = ... go and fetch from your db the corresponding country from the id
// Now build a view model:
var model = new CountryViewModel();
model.CountryId = country.Id;
model.CountryName = country.Name;
// and pass the view model to the view for displaying purposes
return View(model);
}
Now your view will be strongly typed to the view model of course:
#model CountryViewModel
#Html.DisplayFor(x => x.CountryName)
So as you can see in ASP.NET MVC you should always be working with view models. Think in terms of what information you need to work with in a given view and the first thing you should do is define a view model. Then it's the responsibility of the controller action that is serving the view to populate the view model. Where the values of this view model are coming from doesn't really matter. Think of the view model as a single point of aggregation of many data sources.
As far as the views are concerned, they should be as dumb as possible. Simply work with what's available in the view model.
I am trying to create a partial view to display some data. My controller takes in a string itemID and performs a query based on that. When the partial view is called, it displays the same record over and over again.
Note: I changed the name of objects for security purposes.
[ChildActionOnly]
public ActionResult someAction(string itemID = "")
{
//Empty itemID
if(string.IsNullOrEmpty(itemID))
{
return RedirectToAction("Index", "Search");
}
var model = _db.someTable
.Where(r => r.itemID == itemID)
.OrderBy(r => r.col1)
.ThenBy(r => r.col2)
.Take(20);
return PartialView("_myView", model);
}
I have tried removing the OrderBy and ThenBy methods, but the result remain the same, (Order would not matter since they are duplicates...). When I remove the .Where method, it works as expected and displays 20 different records (though, not filtered by any means).
My view was created by Visual Studio using the List template. The view been proven working by removing the .Where method from the LINQ statement. Here are the important bits of the view:
#model IEnumerable<MyApp.Models.OperationData>
.
.
.
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.some column)
</td>
.
.
.
Any ideas as to what is wrong with this query?
EDIT: Tried the other LINQ syntax and ended up with the same results:
var model = from r in _db.someTable where r.itemID == itemID select r;
Winner winner chicken dinner!
Turns out the issue was with the mapping of model to table. The table I was working on has a composite key, which I didn't know about... After reading mipe34's bit about primary keys, I decided to do some investigation into the table structure. After discovering the composite keys, I added the mapping for the 2nd key and all works well.
This issue was extremely confusing since the SQL generated by LINQ worked perfectly fine when run in SQL Management Studio.
Thanks all!
Hit the breakpoint just after the model variable and see what SQL query is generated by LINQ - VS should display it for you. You can also try to execute the query (add .ToList() at the end of the query) to see the actual result, what is in the collection to distinguish if there is a problem in query or view.
I have a ViewBag.People made up from a View;
var query = db.Vw_INTERACTPEOPLE.Select(p => new { p.PersonID, p.Fullname });
ViewBag.People = new SelectList(query.AsEnumerable(), "PersonID", "FullName");
Which all works fine, but in my view I have another model populating a table, and one of the items is populates is an JobcontactID (textbox) which links to the PersonID (i didnt design the database). So I want to search the viewbag for the ID and rather than displaying it I want to display the persons Fullname, so is there any viewbag search functionality?
I would suggest to pass that information in your ViewModel. It will keep it clean and maintainable in long run. Here is a good post: Use ViewModels to manage data & organize code in ASP.NET MVC applications
ViewBag is just a dynamic wrapper around ViewData (which allows the property invoked at runtime to become the key which will be used to look up the value in ViewData). You can query ViewData like this:
SelectList peopleSelectList = (from pair in ViewData
where pair.Key == "People"
select pair.Value);
Update So you wish to query the select list itself?
Here's a function defined in the razor view:
#functions {
public string FindPersonName(string id)
{
return (from item in ViewBag.People as SelectList
where item.Value == id
select item.Value).FirstOrDefault();
}
}
#functions.FindPersonName(jobContactId)