Creating a join using a link table and the Entity Framework - c#

Right now I am struggling with ASP.Net and MVC3 to display a person.
I have a table with the person information, a table for type of person.
A person can be multiple types.
So I created a link table that links the personid and typeid.
I am struggling to find a way to p[ush both the user details and the different types they are part of.
So the ActionResult is taking a PersonID and I can display the person information just fine, but I also need to pass a list of the types they are part of.
Any help, examples or links to a tutorial would be great. Thanks in advance.
Here is what I have right now in my controller.
public ViewResult Details(long id)
{
champion champion = _db.champions.Single(c => c.id == id);
return View(champion);
}
I tried using a ViewBag object and a join statement but it got too complex and went beyond my knowledge of linq statements.

http://msdn.microsoft.com/en-us/library/bb738708.aspx
var champion = _db.champions.Include("TheOtherModel").SingleOrDefault(c => c.id == id);
return View(champion);
and you should've access to "TheOtherModel" by using
champion.TheOtherModel
or in your view:
#foreach (var item in Model.TheOtherModel){
item.Property1
....
}
(should contain a list).

Related

How to combine two queries and get one List in mvc c#

How can I combine these two lists in one List?
public IActionResult Open(int? id)
{
var questions = (from q in _context.Questions where q.CategoryId == id select q).ToList();
var answers = (from s in _context.Answers
join b in questions
on s.QId equals b.ID
group s by b.ID into g
select g.Count()).ToList();
if (questions == null)
{
return NotFound();
}
return View(questions);
}
The problem you are facing is a common one. As already mentioned by #Arripe here, you can create a ViewModel that is a composite class with the properties from each class that you want to use in your presentation layer. With a simple search for "create viewmodel asp.net mvc" or similar, you can find a guide to creating a ViewModel. Yours might be called "QuestionAnswerViewModel".
Constructing the actual ViewModel can be clunky (loop through each collection, mapping properties as you go), or you can be more creative with it.
For example, you could try joining the two query results into a combined result list, with the results being of type .
See #JonSkeet example here: how do I join two lists using linq or lambda expressions
I think what you're trying to get is Questions with number of Answers you have for them, right? If that's the case, then I think this should be the simplest solution. Of course you'll need to update the View to work with the new object.
var questionsWithAnswerCount = _context.Questions.Where(q => q.CategoryId == id)
.GroupJoin(_context.Answers, // list you join with
q => q.ID, // "main" list key
a => a.QId, // joined list key
(q, a) => new { Question = q, AnswerCount = a.Count() } // what to do with result - create new object that has Questions & Number of answers
)
.ToList();
if (questionsWithAnswerCount.Any()) // No need to check for null since you're calling .ToList() which will return an empty list, even when no elements were found, instead call .Any() to check if the list is empty or not
{
return View(questionsWithAnswerCount);
}
return NotFound();
Use a ViewModel to store two list and pass it to the View

Entity Framework Navigation property not working

I have a many to many relationship like below.
Company[CompanyID, Name] - nav prop SalaryTabs
SalaryTab[ID,Salary, Since, CompanyId, Employeeid] - nav prop
(Company, Employee), and
Employee[EmployeeID,FirstName, LastName, DOB] -nav prop
(SalaryTabs)
But When I try to use Linq to query the tables using the navigation property. It wont just show up in the intellisence at all.
For example, I want to access contxt.SalaryTabs.Company.xxx The navigation property Company will not load the xxx and will not show up in the intellisence and if I manually type it. I get some errors.
If I try to do something like
//Delete an employee (identified via id) from a specific company(identified via id)
public bool DeleteEmployeeFromSpecificCompany(Guid employeeID, Guid companyID)
{
try
{
var emp = dbContext.Employees.FirstOrDefault(x => x.EmployeeID == employeeID);
dbContext.Companies.FirstOrDefault(x => x.CompanyID == companyID).SalaryTabs.Employee.Remove(emp);
dbContext.SaveChanges();
}
catch (Exception)
{
return false;
}
return true;
}
The navigation property doesn't work. I can't access context.Companies.SalaryTab.xxxx for example. I have been having this problem since yester which I didn't have before. I could navigate from one entity to another using the navigation properties but now it won't load and offer the options anymore.
I appreciate any input.
SalaryTabs - is collection. So, you need select one:
dbContext.Companies.FirstOrDefault(x => x.CompanyID == companyID).SalaryTabs.FirstOrDefault(...condition...)
I just can't navigate between entities anymore like before. I got the employee entity which i want to remove and the navigation wont let me through. I don't get the option to select the property I want to get to. I tried all day yesterday and it's the same until now.
var emp = dbContext.Employees.FirstOrDefault(x => x.EmployeeID == employeeID);
dbContext.Companies.FirstOrDefault(x => x.CompanyID == companyID).SalaryTabs.Employee.Remove(emp);
dbContext.SaveChanges();

C# class code with data from multiple tables

Hello and thanks taking your time to help me.
When a user login hes User id is stored in a session, and when he enters my Survey page. I want to the page to display the Surveys that is avalible to him.
My Database Diagram:
I tried to Write the code so First it checks if there is any relations between the user and the surveys in the RelationShip table. I have made sure that part works with debugging because it returns 1 since there is 1 user and one survey + the relation with the correct information.
But it cant write the last part like this: lstItem = db.Survey.Where(x => x.ID == relation).ToList(); so it returns the Correct Survey to my repeater. Since there might be more Surveys avaliple to a user.
My class Code:
public class Surveys
{
public static List<Survey> getAll(int id)
{
List<Survey> lstItem = new List<Survey>();
using (KONE_Entities db = new KONE_Entities())
{
List<User_Survey_Relation> relation = new List<User_Survey_Relation>();
relation = db.User_Survey_Relation.Where(i => i.UserID == id).ToList();
if (relation != null)
{
lstItem = db.Survey.Where(x => x.ID == relation).ToList();
}
}
return lstItem;
}
}
My C# code that binds it to the repeater:
private void BindSurvey()
{
int id = Convert.ToInt32(Session["UserID"].ToString());
rpSurveys.DataSource = Surveys.getAll(id);
rpSurveys.DataBind();
}
So to Clarify what Im asking for/ need help with: My Code will not return the Survey or Surveys that has a relation with the user that is logged on to the site.
Thanks for your time and I hope you can help me.
Compare individual relation values and then add the result to lstItem .
foreach(User_Survey_Relation relatSingle in relation){
lstItem.addRange(db.Survey.Where(x => x.ID == relatSingle.SurveyID).ToList());
}
}
Sorry...dude ...compared the whole class,i have edited it...please check if surveyId has to be compared or Id
You can see from the comments what is wrong with your logic. In terms of how best to solve it, I believe your best option is to join your tables in a single query rather than running 2 queries. The SQL syntax would be:
select s.*
from Survey s
inner join User_Survey_Relation usr on s.ID = usr.SurveyID
where usr.UserID = id
Translating this to LINQ becomes (this is rough - I don't have VS to test):
lstItem = (from db.Survey in survey
join db.User_Survey_Relation in relation on survey.ID
equals relation.SurveyID
where relation.UserID = id
select survey).ToList();
Like I say, you may need to play around with this to iron out any wrinkles. Hopefully you get the idea though.

Loading multiple related table data into MVC view. (Linq to SQL)

I seem to be having a problem passing related data to my view. I'm creating a simple blog, which has a database architecture of three tables. These are Users, Posts and Comments. For my user profile page I wish to pass all the data from these tables into the user profile view. I used Linq to SQl to create my database model. Here is my attempt at passing in the data using Linq:
public ActionResult NewProfile()
{
var users = from u in db.UserModels
join p in db.PostModels on u.UserId equals p.UserId
where u.UserId == WebSecurity.CurrentUserId
select new Profile { UserModel = u, PostModel = p };
return View(users);
}
This is the code in the receiving view:
#model IEnumerable<MvcBlog.Models.Profile>
#{
ViewBag.Title = "NewProfile";
}
<h2>NewProfile</h2>
#foreach (var item in Model)
{
#item.UserModel.Username
}
Before I tell you what the result was, I think it's important to give you an idea about the data in my database. Currently, I only have three users. Only one of these users (gb201) has created any blog posts. The user gb201 has created a total of two blog posts.
When I run the program, and log in as user gb201, the data that is displayed on the NewProfile page is:
New Profile
gb201
gb201
The view is being passed the data from two tables, however, when I wish to query the user table, it is duplicating the data based on the number of posts for that user. So if a user only had one post, then it would only display once. For the two other users, who haven't posted anything, there is no information displayed on this page.
I'm assuming that my linq code which is querying the database is wrong, however, I can't seem to think what i'm doing wrong. Sorry for the long question, and any help would be grateful.
What you see is correct as you are building a new Profile per post.
If you simply want one user to be returned you should not join to Post and include the post data afterwards.
var users = db.UserModels.Where(u => u.UserId == WebSecurity.CurrentUserId )
.Include(u => u.Posts)
.ToList()
You can then read each user and then each post in a nested loop.
UPDATE: Now at pc
In your view
#model IEnumerable<MvcBlog.Data.UserModel>
#{
ViewBag.Title = "NewProfile";
}
<h2>NewProfile</h2>
#foreach (var item in Model)
{
#item.Username
//if you wanted the postes per user
foreach(var post in user.Posts)
{
#post.Title
}
}
It would be good practice to create a Model for your view, instead of using your data clas as I have.
UPDATE: To work with Linq to SQL
The above will build a viewmodel that you can use in your view.
var users = db.UserModels.Where(u => u.UserId == WebSecurity.CurrentUserId )
//.Include(u => u.Posts)
.Select(u => UserViewModel{ UserModel = u, Posts => u.Posts})
.ToList()
The answer of NinjaNye is right, but it needs to have the 'new' before the viewmodel call, like this:
var users = db.UserModels.Where(u => u.UserId == WebSecurity.CurrentUserId)
.Select(u => new UserViewModel{ UserModel = u, Posts => u.Posts })
.ToList();

Most efficient way to query a database and then remove entries from returned items

I have a app that allows you to follow peoples blog updates. I have a page where the user can choose who to follow. the people who can be followed are stored in a db ( Table name - Person) and when the user selects someone to follow that is also stored in the db ( Table name - Following).
The problem I have is when the user revisits the page to follow another person, what is the best way to query the database and only display people that the user is not following.
I am using Entity framework.
I have the following working. I need a where statement. followBloggers is returning a list of bloggers that the user is following and Uow.People.GetPeople() is returning all bloggers.
var followedBloggers = Uow.FollowBlogger.GetLinks(companyId).ToList();
return Uow.People.GetPeople().Select(p => new { p });
You could use something like this:
var AlreadyFollowed = currentUser.followBloggers.Select( f => f.Id);
Uow.People.GetPeople().Where( p => !AlreadyFollowed.Contains(p.Id));
Try this (assuming that Following has a FK to People on PersonID):
var followedIDs = user.followBloggers.Select(follow => follow.PersonID);
return Uow.People.GetPeople().Where(p => !followedIDs.Contains(p.PersonID));

Categories