Left join with Code First MVC 4 EF4.1 - asp.net-mvc

I'm creating a system where users have some setting to do to complete their account, see below :
Tables:
SettingsTypes
Id
Name
Settings
Id
FkSettingTypeId
IsEmailActivated
IsSMSActivated
IntervalNotification
So the SettingsType table have these kind of value :
Be warned if time almost over
Be warned about offers in my categories
...
Back into my MVC4 application I need to create a controller that will return every SettingsType with Setting to get a html table where user can choose if he want receive an email and sms for each SettingsType.
I use the Entity Framework 4.1 with CodeFirst and an ordinary page will return the table object like this :
public ActionResult Index()
{
var settings = db.Settings.Include(s => s.SettingsType);
return View(settings.ToList());
}
The include statement make an inner join and do not return all the SettingsType I need associated with the Setting.
How can I write my code to do a left or right join and get the right model to pass into my views like that :
#model IEnumerable<TenderSystem.Models.Setting>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.SettingsType.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.IsEmailActivated)
</td>
<td>
#Html.DisplayFor(modelItem => item.IsSMSActivated)
</td>
<td>
#Html.DisplayFor(modelItem => item.IntervalNotification)
</td>
</tr>}
I tried many thing like these link :
Entity Framework Code First Left Join
Fluent API Samples
But I can't achieve what I expect for.
To conclude, I also use the SQL to LINQ converter tool to convert my very easy SQL left join into LINQ and may be return the object I can use into my view but I got this error : Only parameterless constructors and initializers are supported in LINQ to Entities.
Need your help to understand the right thing to do with this situation.
Thank you very much

I think the Include can just be the child's model name as a string under one of the constuctors. Here is a link for EF5.
http://msdn.microsoft.com/query/dev11.query?appId=Dev11IDEF1&l=EN-US&k=k("System.Data.Entity.Infrastructure.DbQuery`1.Include");k(Include);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5);k(DevLang-csharp)&rd=true
or shortened...
http://bit.ly/SOEttF
I am using WebAPI so the return wants an IQueryable and this works for me.
[AcceptVerbs("GET")]
public IQueryable<Run> Runs()
{
var rx = _contextProvider.Context.Runs
.Include("RunOutlineItems")
.AsQueryable()
.Where(r => r.RunStatusId < 4);
return rx;
}
also check this answer
Join and Include in Entity Framework

Related

Entity Framework IQueryable with join

I'm new with Entity Framework and razor pages, I´m very familiar with asp classic, but know I'm trying to learn something more actual.
How can I retrieve values from a join query in a model to the page/view.
In model I have:
IQueryable<TabQuotas> quotasIQ = from s in _context.TabQuotas
join s2 in _context.ApplicationUser
on s.Socio equals s2.Socio
select s;
And in page/view:
#foreach (var item in Model.TabQuotas) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Socio)
</td>
<td>
#Html.DisplayFor(modelItem => item.Nome)
</td>
<tr>
}
"item.socio" which is from the first table in join, works perfect, but "item.Nome" which is from the second table, I can't find out how to retrieve the value from the query. It keep telling me that "TabQuotas" does not contain a definition for "Nome"...
Could someone help me with it?
I figure it out by my self.
For those how could have the same question, here is the answer.
First of all we have to create a model with all the values we want to retrieve from the data base.
Then on the .cs file:
var quotasIQ = from s in _context.TabQuotas
join s2 in _context.ApplicationUser
on s.Socio equals s2.Socio
select new ListQuotas
{
Id = q.Id,
Email = n.Email
};
Where ListQuotas is model class we created before.
And that's it.
I hope I can be useful to someone.

ASP.NET MVC creating Model from Database (Postgres)

Please forgive me if this question is too stupid but I just started learning ASP for few days...
So I decided to make some simple Web application which will dispaly data from database (Postgres).
To connect to DataBase I using NpgsqlConnection class. I saw few tutorials how to connect to DB i.e. here, but almoust everywhere they are using MSSQL and nowhere I cant find solutions for my case.
So I would like to have model which will be contains all fetched data within I will be able to iterate like this:
<% foreach (var item in Model)
{ %>
<tr>
<td><%: item.Title %></td>
<td><%: String.Format("{0:g}", item.ReleaseDate) %></td>
<td><%: item.Genre %></td>
<td><%: item.Rating %></td>
<td><%: String.Format("{0:F}", item.Price) %></td>
</tr>
<% } %>
So How I should do to achieve this?
I thought to create class
public class Person{
int id;
string Name;
string Surname;
...
}
next create generic List of type Person and after fetch data, add all fetched data to my List. And then somehow pass this List as Model.
I think there is some better way to do it right. Any Suggest?
Nope, you're pretty much on track.
The main difference you see from the tutorials is most of them are probably using entity framework to populate the models. Since you're using postgres...i wouldn't really recommend trying to get entity framework to work with it (I heard it's a nightmare). You can use a different Orm if you like, or just do it with your connection command and reader like you're probably used to.
The way I would do it is create a domain model that looks like just like the database model (looks like what you did with Person)
From there you would populate it in a Controller.
public class PersonController : Controller
{
//this method will map to the Person/Index route by default
public ActionResult Index()
{
//use your npgsqlconnection right now to populate whatever object you'd like
List<Person> people = PopulateFromPostgres();
//here were returning the index view with the model being a list of person
return View(people)
}
}
Then in your view (Views/Person/Index.cshtml i believe in this example)
#model List<Person>
<table>
#foreach (var item in Model)
{
<tr>
<td>#item.Title</td>
<td>#String.Format("{0:g}", item.ReleaseDate)</td>
<td>#item.Genre</td>
<td>#item.Rating </td>
<td>string.Format("{0:F}", item.Price)</td>
</tr>
}
</table>
Let me know if there's more specific area you don't understand here.

Why does this lambda expression work?

I found this Related Topic, but it failed to answer my question.
When automatically creating a strongly typed view, lets say with a List scaffolding template, I will get something roughly like this:
#model IEnumerable<Test.Models.abc>
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.ID)
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.ID)
</td>
</tr>
}
</table>
I understand #Html.DisplayNameFor(model => model.ID) completely, but not #Html.DisplayFor(modelItem => item.ID).
What is the purpose of modelItem? Replacing it with any arbitrary text will result in a functional web page. It seems that modelItem is just a throwaway word. I guess my real question is why doesn't this work?
#Html.DisplayFor(item => item.ID)
Edit
A good point was brought up in the comments. It seems you are also able to change model to anything so long as you change it on both sides of the lambda expression:
#Html.DisplayNameFor(abc => abc.ID)
A side question would be: How does the #model statement at the top affect the functions below? I had previously thought model referenced the #model expression in order to figure out the display name via the class, but the page still works after the mentioned changes.
It does not work because item is already declared in outer scope in foreach.
#foreach (var item in Model).
The reason why modelItem lambda is not used is because of that iteration of IEnumerable. If there would be Test.Models.abc as model instead of IEnumerable, then would that lambda does matter and the code of DisplayFor would change to #Html.DisplayFor(m => m.ItemId).
Update
#model IEnumerable<Test.Models.abc> just declares that this view is strongly typed, with type of IEnumerable<Test.Models.abc> - in your case. That means that view property this.Model (not model) is of type IEnumerable<Test.Models.abc> - and also that model of that type should passed into this view. model in example above is just expression variable - it has scope just for that expression. You can change it's name to any unprotected legal variable name that was not already used in outer scope (that's why it should not be named Model, because it would hide the Model property already declared in view).
item is already a variable defined in an outer scope. You are capturing it as a closure, which is not ideal here. What your code should read is:
#Html.DisplayFor(modelItem => modelItem.ID)

asp.net mvc - pass partial data model to partial view

I wish to build a partial view that gets a model column and print it.
Something like that:
At the view:
#model IEnumerable<products_comparison.Models.Product>
#{
ViewBag.Title = "Index";
var Brand = (from r in Model
select r.Brand).Distinct();
}
<h2>
Index</h2>
#Html.RenderPartial("_DisplayAttribute",Brand)
And at the partial view:
<table>
<tr>
<th>
Brand
</th>
</tr>
#foreach (var row in Model)
{
<tr>
<td>
#Html.DisplayFor(r => row)
</td>
</tr>
}
</table>
There are a few problems I run into:
The compiler doesnt allow me to send Barnd to the partial view.
If you look at the partial view code you will see the word Brand, which is the column name. I dont wish to hard-coded the word "Brand" in the partial view, instead I like that the column name will be there.
In the partial view I need to put #model products_comparison.Models.Product, but I dont
want to send the hole table. I want to send only one column - But I dont know what to put there..
Thanks!
EDIT:
Just to clear one thing, I want that the view will call the same partial view for each column in the table(for most of the columns in the table anyway) and each time I'll send a different column(distinct value column to be exact).
Start by refactoring and putting the right logic into the right place. This LINQ query has strictly nothing to do in a view. A view is not supposed to do any LINQ queries or whatever to pull data. A view is supposed to work with data that it is passed to it from the controller action under the form of a view model. A controller action builds and passes an adapted view model that you define for the view.
So as always you start by defining a view model that will be adapted to the requirements of your view:
public class MyViewModel
{
public IEnumerable<Brand> Brands { get; set; }
}
then you write a controller action that will populate this view model and pass it to the view:
public ActionResult Foo()
{
IEnumerable<products_comparison.Models.Product> products = ...
var model = new MyViewModel
{
Brands = (from r in Model select r.Brand).Distinct()
};
return View(model);
}
then a view:
#model MyViewModel
<table>
<tr>
<th>
Brand
</th>
</tr>
#Html.DisplayFor(x => x.Brands)
</table>
and finally you could define a corresponding display template which will automatically be rendered for each element of the Brands collection of your view model (~/Views/Shared/DisplayTemplates/Brand.cshtml):
#model Brand
<tr>
<td>
#Html.DisplayForModel()
</td>
</tr>
For 1 try changing #Html.RenderPartial("_DisplayAttribute",Brand) to #Html.Partial("_DisplayAttribute",Brand)
You will also need to specify the model in the partial view like #model products_comparison.Models.Brand or something like it
Also please clarify 2 & 3 as they are not clear what you want

Pre-select object properties using lambda expressions, then display in MVC?

Currently in MVC, we have to define columns manually whenever we want to list out items:
<tr>
<td>
#Model.Name
</td>
<td>
#Model.Age
</td>
<td>
#Model.Gender
</td>
</tr>
What I want to do however, is to have a ViewModel where we specify which columns should be used, something like:
var model = new PersonViewModel(
// List of persons
CollectionOfPersons,
// List of columns that we want to display
new Expression<Func<Person, object>>[]
{
x => x.Name,
x => x.Age,
x => x.Gender
});
Then in our view, all I need to do is:
<tr>
// Model.Predicates is our ViewModel's selected columns
#foreach(var predicate in Model.Predicates)
{
<td>
// This would basically loop each pre-defined lambda expression in our ViewModel
#Html.DisplayFor(predicate)
</td>
}
</tr>
I have to admit I have a very weak understanding of expressions, and I have so far been unsuccessful in looking for information. Does anyone have any idea if this is possible to do?
Seems like the html helpers don't work like that (passing in the expression as a variable). The compiler explicitly needs an expression to be able to determine the TModel and TResult types to be able to work.

Resources