C# class code with data from multiple tables - c#

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.

Related

Obtain more information from the user via Inner join Linq

I supposed in the process developed is such that it must show all the movies that are into film tablen and showing off, but this is how I have tried to do this:
it must find out which genres have in users tablen where after to show the users who like the first.
//As I said, I have a session at the top of the code.
int brugerid = Convert.ToInt16(Session["id"]);
var result = (from f in db.films
//it must find out which genres have in users tablen where after to show the users who like the first.
//brugere are users
//gener It is the genes users like.
join usersgenerId in brugere.Fk_generId on gener.generId equals usersgenerId.BrugereId
select new
{
image_navn = ((f.imgs.FirstOrDefault(i => i.feature == true)).navn == null ? "default.png" : (f.imgs.FirstOrDefault(i => i.feature == true)).navn),
image_feature = f.imgs.Where(A => A.feature == true),
film_navn = f.navn,
film_id = f.filmId,
film_tekst = f.tekst,
film_gener = f.gener.navn
}).ToList();
RepeaterFilmList.DataSource = result;
RepeaterFilmList.DataBind();
Table information
Brugere the name
id = BrugereId
Fk_generId belonging to the genes that user has selected.
and many other
Gener is the name
has generId as id
As mentioned in the comment, the question really is: show all movies that is in the same genre that the user preferred and then show everything else.
Although the following approach might not be db efficient (too lazy to create the db for this, so I am simulating everything in memory and using Linq to Object to solve the issue), it can certainly be resolved by the following steps:
Get the recommendation (matching the user's movie genre preference) like so:
var recommendation =
from f in films
from ug in userGenres
where ug.UserId == user.Id && ug.GenreId == f.GenreId
select f;
Now that we know what the user preferred, we can further filter this to just the preferred films' Id... and use that to get the rest of the unpreferred films (basically anything not matching the preferred film Ids):
var recommendedFilmIds = recommendation.Select(f => f.Id);
var everythingElse =
from f in films
where !recommendedFilmIds.Contains(f.Id)
select f;
Finally, join them together using Union and injecting the nessary fields for display purpose like Genre.Name, etc. like so:
var filmList = recommendation.Union(everythingElse).Select(f => new {
f.Id,
f.Title,
Genre = genres.Where(g => g.Id == f.GenreId).Select(g => g.Name).First()
});
And there you have it, the combined list will now contains both preferred films first (at top), followed by unpreferred films afterward.
The simulated tables are as follows: films which contains its own Id and genreId and userGenres which contains many to many relationship between user and genre and a particular user object which contains the user id.
An example of this can be found at: https://dotnetfiddle.net/Skuq3o
If you use EF, and you have a navigation property to genre table and you want to include those table as part of the query, use .Include(x => x.genre) or whatever you call your genre table after from f in films to avoid n+1 select if you wish to include the genre info in the final select clause.

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();

Reading related data from two entities using LINQ

I have a one to many relationship of Users to Certificates. In my view I am able to see all data from Certificates and related data from Users. However this view gives me a repeat of UserID and is not effective. Please see this question here first.
In this view I used this query
var certUser = var cert = db.Certificates.Include(c => c.Users);
var AllcertUser = from s in certUser select s;
return View(AllcertUser.ToList());
Since UserID is distinct from this controller with this LINQ code:
var Allusers = from s in db.Users
select s;
return View(Allusers.ToList());
I get distinct Users from the code above. When I try to include from Certificates class, this is where I am failing to make it work. I need to include the Certificates so that I can have values from that entity which are related. I hope I made myself clear.
This is part of what I need. When Details are clicked the UserID must be passed and their details shown. At the moment I have hard coded id 23. How to pass the user id to the details view so that I get the certificates details.
public ActionResult Details(int id)
{
cpdEntities db = new cpdEntities();
var UserCerts = db.Certificates.Where(x => x.UserID == 23).ToList();
return View(UserCerts);
}
If I understand you correctly, you want to join tables and return all certificates grouped by users:
var query = from u in db.Users
join c in db.Certificates on u.UserID equals c.UserID into g
select new { User = u, Certificates = g };
Or you can pre-load Certificates (if lazy-loading is disabled):
var query = db.Users.Include(u => u.Certificates);
The reason you see multiple UserIds is because you are querying the Certificate entity, which as you said yourself, has a m:1 relationship with Users. If your view is a master-child type form and you want to see only one row per user, do the query the other way round:
var users = db.Users.Include(u => u.Certificates);
In your view you can iterate through each user's Certificate collection as required. For example, depending on the design of your view, you might just want to display certificates for one selected User.

Creating a join using a link table and the Entity Framework

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).

How do I get all the elements and if they are assigned?

I have the following model.
Subscription Packages PackageWidgets Widgets
------------ -------- -------------- -------
ID ID < PackageID ID
PackageID > WidgetID >
I am using Entity Framework 4 and a Subscription has a relationship to Package. And Package has a relationship to a list of Widgets.
Using Linq, I am trying to get a listing of all Widgets and if they are included in the current subscription. Perhaps it's due to my SQL background that I'm just not seeing the query in Linq. SQL would involve a SELECT from Widgets, with a LEFT JOIN through a subselect of Subscriptions, Packages and PackageWidgets based on the passed in SubscriptionID.
The output I would expect would be something like WidgetID,IsIncluded such that I would have all Widget IDs and a boolean indicating the inclusion status.
I cannot seem to even get something remotely close to working in order to show what I've done so far.
Can anyone provide me with some insights on how to accomplish my query?
Update:
Here is what I've come close with, but it still doesn't work. Maybe it will help illustrate what I am trying to accomplish though:
from subscription in Subscriptions
where subscription.ID == 3
let subWidgets = subscription.Package.Widgets
from widget in Widgets
join subWidget in subWidgets on widget.ID equals subWidget.ID into joined
from list in joined.DefaultIfEmpty()
select new {
ID = widget.ID
,Selected = subWidget.ID != null
}
Update #2
Thanks to the accepted answer, this is what I ended up going with - which does what I need:
from widget in Widgets
from subWidgets in
from subscription in Subscriptions
where subscription.ID == 3
select subscription.Package.Widgets
orderby widget.ID
select new {
Name = widget.WidgetName,
Available = subWidgets.Contains(widget)
}
Thanks for the assist!
One way to approach it is breaking it up, so something like:
var widgetsInSubscription =
from subscription in Subscriptions
where subscription.ID == 3
from widget in subscription.Package.Widgets
select widget;
var allWidgets =
from widget in Widgets
select new
{
widget.ID,
Selected = widgetsInSubscription.Contains(widget),
};
Or doing it based on the ID's instead of the objects, something like:
var widgetIDsInSubscription =
from subscription in Subscriptions
where subscription.ID == 3
from widget in subscription.Package.Widgets
select widget.ID;
var allWidgets =
from widget in Widgets
select new
{
widget.ID,
Selected = widgetIDsInSubscription .Contains(widget.ID),
};
Keep in mind that you can always do the query yourself if you want - in EF4 you can just call ExecuteStoreQuery with your own SQL
Something like:
from s in db.Subscriptions
from p in db.Packages
from pw in db.PackageWidgets
from w in db.Widgets
where w.ID == pw.WidgetID &&
pw.PackageID == p.ID &&
s.PackageID == p.ID
select w;
Dunno if it works though. However, if you had properties like myPackage.Subscriptions etc, this could probably be simplified a lot.

Categories