Retrieving data from a one-to-many relationship - asp.net-mvc

I'm trying to retrieve data from a one-to-many relationship, in an ASP.NET MVC application.
Let's say I have two tables Posts and Category with the following attributes:
posts
-id
-title
-category_id
category
-id
-name
-author
I want to grab posts that belong to a category and grab the values of .name and .author from the category.
This is what I have in the model:
public IQueryable<Post> GetPosts()
{
return from post in db.Posts
join categories in FindCategories()
on categories.id equals post.category_id
select new
{
title = post.title,
name = categories.name,
author = categories.author
};
}
And in the controller:
public ActionResult Index()
{
var allposts = postRepository.GetPosts().ToList();
return View(allposts);
}
The model complaints that it can't convert and IQueryable of Anonymous type into an IQueryable < Post >. I suspect it's because I'm doing Select new { }, but I'm not sure.
If I do IQueryable only then I don't have the ToList() method available in the view.
So, I'm lost. Can you help?
(an by the way, I'm a complete newbie at this asp.net mvc thing.)

I think the problem is that you're trying to use a var outside of the scope of a single method. In your projection stage try newing-up a Post object rather than an anonymous type. e.g.
public IQueryable<Post> GetPosts()
{
return from post in db.Posts
join categories in FindCategories()
on categories.id equals post.category_id
select new Post()
{
title = post.title,
name = categories.name,
author = categories.author
};
}

The question has been answered by Lazarus in the comments. Your method declaration states a return type of IQueryable of Post types
public IQueryable<Post> GetPosts() { //...
But your linq projects to an anonymous type and returns an IQueryable of anonymous types
select new { //anonymous type
title = post.title,
name = categories.name,
author = categories.author
}; // = IQueryable<SomeCompilerGeneratedTypeNameHere>
You need to define a new type
public class PostDisplay {
public string Title { get; set; }
public string Name { get; set; }
public string Author { get; set; }
}
then in your code return an IQueryable of that type
public IQueryable<PostDisplay> GetPosts() {
return from post in db.Posts
join categories in FindCategories()
on categories.id equals post.category_id
select new PostDisplay {
Title = post.title,
Name = categories.name,
Author = categories.author
};
}

Related

Asp.net mvc call entity db data using Id for that particular row

Hi and thank you for taking your time to read. I am having trouble calling from a db using entity framework for a particular row. Here is my code for controller.
public ActionResult MyAccount(CurrentAccount ca, SaverAccount sa, int id)
{
var model = db.CurrentAccounts.FirstOrDefault(_ => _.Id == id);
Session["Id"] = ca.Id;
Session["CurrentAccountNumber"] = ca.CurrentAccountNumber;
Session["CurrentBalance"] = ca.CurrentBalance;
Session["SaverAccountNumber"] = sa.SaverAccountNumber;
Session["CurrentBalance"] = sa.SaverAccountNumber;
return View(model);
}
My model is a edmx entity file and i can seem to retrieve some data to my locals but only from 1 table and i need data to be from multiple tables selecting a full row of data for a paricular Id then having this information visable on the same view. There is also a relation between id on both tables. Thanks :)
Here you have called wrong object because you are fetching data in model variable but calling from ca. please use as following
public ActionResult MyAccount(CurrentAccount ca, SaverAccount sa, int id)
{
var model = db.CurrentAccounts.FirstOrDefault(_ => _.Id == id);
Session["Id"] = model.Id;
Session["CurrentAccountNumber"] = model.CurrentAccountNumber;
Session["CurrentBalance"] = model.CurrentBalance;
Session["SaverAccountNumber"] = sa.SaverAccountNumber;
Session["CurrentBalance"] = sa.SaverAccountNumber;
return View(model);
}
You need to execute join query to get data from two models like following exmaple
Create a common class like follwing
public class datafrombothclass
{
public int Id { get; set; }
public String saveaccount_name { get; set; }
public String currrentaccount_name { get; set; }
}
Now use join query in entity framework to get data from both model in you case from CurrentAccount and SaverAccount.
See the bellow code example:
var frombothclass=(from a in Model.saveaccount join s in Model.currentaccountaccount
where a.Id=id
select new datafrombothclass{
Id=a.Id,
saveaccount_name=s.name,
currrentaccount_name=a.name
});
return View(frombothclass);
Hope you will get the solution.

How do I loop through an array and add each value to my model variable? MVC Razor

I am trying to make a variable in my model that retrieves all available skills to later display them in a DDL. I have one variable that contains all of the skills and one variable that displays all of the skills an employee has already rated. I want to check all of the skills against the rated skills so that only the unrated skills are added to the new variable in the model. The only way I could think of to do this is to use a foreach loop to check for the values in the AllSkills variable.
model:
public IEnumerable<long> AvailableSkills { get; set; }
public IEnumerable<long> AllSkills { get; set; }
public IEnumerable <long> EmployeeRatings { get; set; }
public IEnumerable<Rating> Ratings { get; set; }
public IEnumerable<Skill> Skills { get; set; }
public long SkillId { get; set; }
Controller:
model.AllSkills = db.Skills.OrderBy(s => s.SkillName).Select(s => s.SkillId);
model.EmployeeRatings = db.Ratings.Where(r => r.EmployeeId == User.Identity.Name.Remove(0, 8)).OrderBy(s => s.SkillId).Distinct();
foreach (var skill in model.EmployeeRatings)
{
model.AvailableSkills = model.AllSkills.Where(s => s != skill);
}
I want to do something like the following code in the foreach loop:
model.AvailableSkills += model.AllSkills.Where(s=> s != skill); but this is not allowed.
The problem is that this for each loop above is assigning the model.AvailableSkills to the every skill but the last one that is in the foreach loop (as it should). How do I make it so that every one of the duplicate skills are excluded from model.AvailableSkills?
Using LINQ is IMO more readable if you use to query syntax opposed to the method chaining syntax.
model.AllSkills =
from skill in db.Skills
orderby skill.SkillName
select skill.SkillId;
model.EmployeeRatings =
from rating in db.Ratings
let employeeId = User.Identity.Name.Remove(0, 8)
where rating.EmployeeId == employeeId
orderby rating.SkillId
select rating.SkillId
You can use the Except() extension method to remove items from the collection.
// exclude the 'owned' skils
model.AvailableSkills = model.AllSkills.Except(model.EmployeeRatings);
And you probably want to distinct the results:
model.AvailableSkills = model.AvailableSkills.Distinct();
Last but not least:
Because you select the SkillId I'm unsure why you would order the results. This does not make sense especially because you order by different properties in both lists. Furtermore you probably want to select more details to display to the user, but to know this we need more details on your model.
Assuming EmployeeRatings contains rated skills, and you want AvailableSkills to have only skills not in EmployeeRatings but are in AllSkills, I think this is what you like to do:
model.AvailableSkills = model.AllSkills
.Where(s => !model.EmployeeRatings.Contains(s));
Consider two classes like this:
public class Skill
{
public int Id { get; set; }
}
public class Employee
{
public int[] RatedSkills { get; set; }
}
var skills = new List<Skill>
{
new Skill{ Id = 1}, new Skill{Id = 2}, new Skill{ Id = 3}, new Skill { Id = 4}
};
var emp = new Employee
{
RatedSkills = new int[] { 1,2 }
};
var availableSkills = skills.Select(s => s.Id).Except(emp.RatedSkills);
Console.Read();
The rating has an Id property an an employee has an int[] to hold his/her selected ratings. From there it's easy to filter
Following your current approach, you can use AddRange with a list. Something like:
List<long> availableSkills = new List<long>();
foreach (var skill in model.EmployeeRatings)
{
availableSkills.AddRange(model.AllSkills.Where(s => s != skill));
}
model.AvailableSkills = availableSkills;
Or you can achieve this with a more compact approach, and I believe Except removes dupes:
model.AvailableSkills = model.AllSkills.Except(model.EmployeeRatings);

Enity Framework query result shaping

Based off the MVC Music Store sample, I'm trying to pre-fetch the albums along with the genre but only read specific data from the album and not the complete entity.
Here is the EF query:
public ActionResult Browse(string genre)
{
// Retrieve Genre and its Associated Albums from database
var genreModel = storeDB.Genres.Include("Albums").Single(g => g.Name == genre);
return View(genreModel);
}
Say I have a View Model with:
public class AlbumViewModel
{
public string Title { get; set; }
public decimal Price { get; set; }
}
How would I alter the EF LINQ query to get both the genre info AND include the albums but only select the data listed in the View Model, not the enitire entity?
To do the View Model part, I would have done something like (VB):
From a In storeDB.Albums
Where a.Genre = genre
Select New AlbumViewModel With {
.Title = a.Title,
.Price = a.Price,
})
This should be it:
(from g in storeDB.Genres
where g.Name == genre
select new {
Genre = g,
Albums = g.Albums.Select(a => new { Title = a.Title, Price = a.Price })
})

pass an anonymous type to my ASP.NET MVC view

I have a problem, I have the next controller
namespace RolesMVC3.Areas.Administrador.Controllers
{
[Authorize(Roles = "Adminr")]
public class HomeController : Controller
{
private BASEDATOSCJ_2Entities db = new BASEDATOSCJ_2Entities();
public ActionResult Index()
{
string username = User.Identity.Name;
MembershipUser user = Membership.GetUser(username);
Guid key = (Guid)Membership.GetUser().ProviderUserKey;
var Universities = (from u in db.UNIVERSITy
join s in db.CAMPUS_UNIVERSITy on u.IdUniversity equals s.IdUniversity
join c in db.CIUDAD_CAMPUS on s.IdCiudadSede equals c.IdCiudadSede
join co in db.OFFICE on s.Idoffice equals co.Idoffice
join uxc in db.USERxOFFICE on co.Idoffice equals uxc.Idoffice
where uxc.UserId == key
select new { u.Name, namecity = c.Nombre, s.Idoffice}).ToList();
return View(Universities);
}
With this controller I just want send to View u.Name, and s.Idoffice. How I do? (in fact do not know if this controllet is fine), I want to send fields belong to different tables. I want to send the query as a list and present at the View, ViewBag go with it?, How do I pass these data to the view and display with a foreach?.
I use razor
If you change the following line:
select new { u.Name, namecity = c.Nombre, s.Idoffice}
To
select new { Name = u.Name, Idoffice = s.Idoffice }
This only selects the two fields into a list. In your view you can do the following:
#model List<dynamic>
#foreach(dynamic d in Model) {
<p>#d.Name</p>
<p>#d.Idoffice</p>
}
Edit:
You might want to define a ViewModel to contain your data.
public class MyViewModel {
string Name {get;set;}
string Idoffice {get;set;}
}
Now you can change your select statement as follows:
select new MyViewModel { Name = u.Name, Idoffice = s.Idoffice }
And update your Razor file as such:
#model List<MyViewModel>
#foreach(MyViewModel d in Model) {
<p>#d.Name</p>
<p>#d.Idoffice</p>
}
I would use a view model. I have learnt not to expose my domain objects to the view, I rather map my domain object to the view model and return this view model to the view.
Separate you data access logic from your view logic. You can put that whole statement into a repository class and then you just call this method from the controller.
Here is a partial view model, you might have more properties if you need more data to be displayed:
public class UniversityViewModel
{
IEnumerable<University> Universities { get; set; }
}
University class:
public class University
{
public string Name { get; set; }
public string Idoffice { get; set; }
}
In my action method of my controller it would look something like this:
public ActionResult Index(int id)
{
UniversityViewModel viewModel = new UniversityViewModel
{
Universities = universityRepository.GetAll()
};
return View(viewModel);
}
And in my view I would have the following:
<table>
#foreach(University university in Model.Universities)
{
<tr>
<td>Name:</td>
<td>university.Name</td>
</tr>
}
</table>
This is just a basic display of data in the view, you can use 3rd party components to display your data with some features.

LINQ: Why am I getting error on this LINQ Query?

This my method in my repository:
public List<Question> getallquestion()
{
var hej = from Core in db.CoreValue
join Question in db.Question on Core.CID equals question.QID
join Subject in db.SubjectType on Core.CID equals Subject.SID
select new
{
Core.Cname,
Question.QuestionText,
Subject.Sname
};
return hej.ToList();
}
This is the error:
Cannot implicitly convert type 'System.Collections.Generic.List<AnonymousType#1>' to 'NKI3.Models.Question'
What is the solution for this error? I cant seem to find it
My CreateViewModel:
public class CreateViewModel
{
public string QuestionText { get; set; }
public string Sname { get; set; }
public string Cname {get;set;}
}
}
Thanks in Advance!
Best Regards!
Your linq query produces List of anonymous object (as you use select new { (...) } without any type). You should replace it with select new Question() { (...) }. You should check that select syntax depending on Question class properties.
eg. When you have Name, Text and Subject property is should look like this:
var hej = from c in db.CoreValue
join q in db.Question on c.CID equals q.QID
join s in db.SubjectType on c.CID equals s.SID
select new Question
{
QID = q.QID,
QuestionText = q.QuestionText
};
Change your select to read like so:
public List<CreateViewModel> GetAllQuestionViewModel()
{
var hej = from Core in db.CoreValue
join Question in db.Question on Core.CID equals question.QID
join Subject in db.SubjectType on Core.CID equals Subject.SID
select new CreateViewModel
{
Cname = Core.Cname,
QuestionText = Question.QuestionText,
Sname = Subject.Sname
};
return hej.ToList();
}
In your controller you would do something like this:
public ActionResult Index() {
IEnumerable<CreateViewModel> questions = someContext.GetAllQuestionViewModel();
return View(questions);
}
Your method is expecting to return a collection of your Question type, but your LINQ query is returning a sequence of an anonymous type. You should change your query, for example changing your projection:
public List<Question> getallquestion()
{
var hej = from Core in db.CoreValue
join Question in db.Question on Core.CID equals question.QID
join Subject in db.SubjectType on Core.CID equals Subject.SID
select new Question
{
Name = Core.Cname,
Text = Question.QuestionText,
Subject = Subject.Sname
};
return hej.ToList();
}
This is using an object initializer to assign the property values of the Question type from the result of the query. Your property names will differ.
You can't return an anonymous type.
Create a class
public class QuestionResult
{
public string Core {get; set;}
public string Question {get; set;}
public string Subject{get; set;}
}
and use it
public List<QuestionResult> getallquestion()
{
var hej = from Core in db.CoreValue
join Question in db.Question on Core.CID equals question.QID
join Subject in db.SubjectType on Core.CID equals Subject.SID
select new QuestionResult
{
Core = Core.Cname,
Question = Question.QuestionText,
Subject = Subject.Sname
};
return hej.ToList();
}

Resources