How to access 2 tables' relationship in a view in MVC - asp.net-mvc

In my program I have two tables/models: Users and Groups in a many-to-many relationship.
When someone is logged in, I want to expose certain links that only Users in that specific Group can access.
Now in my view if I do:
#using (var dbContext = new DatabaseContext())
{
var user = dbContext.Users.First(p => p.Id == SecurityContext.CurrentUser.Id);
if (user.Groups.Count() < 1)
Debug.WriteLine("Less than 1");
}
And the list is always empty.
Is this something that view models are meant for? I need to somehow access both tables to find if a certain user is in a certain group.

You have to load related entities
var user = dbContext.Users.Include("Groups").First(p => p.Id == SecurityContext.CurrentUser.Id);
Read more about loading related entities on MSDN

Related

Is it possible to reference another table so that an employee record is associated with a user record?

I am attempting to build a web app that allows users to view company policies, procedures, newsletters, and their own employee information.
I have my staff table that contains all the employee information (along with related lookup tables for things like prefix, staff grade, etc)
my app uses asp-identity for the login functionality, but I want to be able to return information from the staff table that is only relevant to that particular user.
I know it is possible to extend the ASP.net users table to include custom fields, but this doesn't really suit my goal as the staff table is used in a desktop based app by the admin team.
Add a field to your Staff table UserId for example ALTER TABLE Staff ADD UserId NVARCHAR(256) DEFAULT NULL;
Optionally, you would reference the AspnetUsers table.
Update Staff table rows in other to set UserId values to related users ids (manually or create an action to do that)
Then, In your the controller, you can select newsletter from table where employee's user id equal connected User.Identity.Id. for example
var news = context.Newsletters.Where(n=>n.Staff.UserId==User.Identity.Id);
var infos = context.StaffInfos.Where(si=>si.Staff.UserId==User.Identity.Id);
in case the tables are not in relationship, you'll need to do like following
var employee = context.Staffs.FirstOrDefault(s => s.UserId == User.Identity.Id);
if(employee != null) {
var infos = context.StaffInfos.Where(si=>si.IdEmployee==employee.EmployeeId);
return View(infos);
} else {
return Content("You don't have an account associated to your staff info...");
}
Please replace fields in these queries with the names of your fields.

Entity Framework strategy/approach

Well, here goes another noob question: So I made this app where different customer have access to their accounts. Everything is ok, they login, by roles I can get who gets what though entity framework. The thing is, with time, the database will grow A LOT. For example: Customers have access to their "bills to pay". For now, there are only a couple thousand of them and a simple "Where" lambda expression can do the trick. But as said, the base will grow.
The scenario: Every record, has a "company" field, which determines the company which the record belongs to. Users have roles, where I store what companies that specific user can access data. So one user can access multiple companies data if it is configured this way.
My question is: Is there a way to initialize entity framework scope passing on the user's roles so the scope contains data which "belong" to that user? Something like:
using (MyThingy scope = new MyThingy(user.Roles))
{
//scope.Bills here will contain only bills which "payer" or "holder"
//are companies within user.Roles
List<Bill> billsToPay = scope.Bills.Where(c =>
c.DueDate == DateTime.Now);
}
So, is it possible? If so, what would be the best approach?
There are many ways to do this. You may want to read up on joins. Here are a couple of approaches that may work:
// brings back a lot of Bills from the db into memory......
using (DbContext scope = new DbContext())
{
//scope.Bills here will contain only bills which "payer" or "holder"
//are companies within user.Roles
IEnumerable<Bill> billsToPay = scope.Bills.Where(c => c.DueDate == DateTime.Now );
// this part happens in memory
List<Bill> bills = billsToPay
.Where(c => user.Roles.Any(role => c.payer == role.payer || c.holder == role.holder))
.ToList();
}
// more efficient.. I did this from memory. Syntax may not be perfect....
using (DbContext scope = new DbContext())
{
//scope.Bills here will contain only bills which "payer" or "holder"
//are companies within user.Roles
var query = from u in scope.Users
from role in u.Roles
from b in scope.bills.Where(b => b.DueDate == DateTime.Now && (b.roleID == role.roleID || b.holderID == role.holderID))
where u.userID == user.userID
select b;
}

MVC EF get many-to-many relationship table

I set up my many-to-many relationship in EF. But I can only refer to the main tables, not the bridge table. How can I refer to the bridge table?
for example:
User: UserID, name
Group: GroupID, group
UserGroup: UserID, GroupID
I can refer to the User table and Group table by typing
context.User.(some linq expression)
context.Group.(some lin1 expression)
But I cannot refer to the bridge table by typing
context.UserGroup
It would be great to know which versions of MVC and EF you are working with. Based on the assumption that its MVC 4 and EF5...
The point of a Join table is to keep referential integrity going. As #timothy says, there is no reason to refer to the (UserGroup) Join table unless there is actual additional data in it i.e. payload. If you're putting other data in the UserGroup table then its not a Join table anyway.
Rather use some Lazy or Eager loading to get the Group data you need:
Lazy Loading
var users = context.Users
foreach (User x in users)
{
foreach (Group f in x.Groups)
//notice the x user being referred to here for Groups
{
// Whatever you want to do with the objects
}
}
Eager Loading
var users = context.Users.Include(g => g.Groups)
foreach (User x in users)
{
foreach (Group f in x.Groups)
//notice the x user being referred to here for Groups
{
// Whatever you want to do with the objects
}
}
The 'foreach' code above is just added to show how to include it in a loop example. Its the first line of these Loading examples that are important.
Once you have defined 'var users' the rest is "easy".
Good Luck!
When defining a many-to-many relationship you have two options.
Link User to Group, and let it know that UserGroup is your join table
Link User to UserGroup as many-to-one, also link Group to UserGroup using many-to-one.
The reason to use option 2 is when you have something other than just the two IDs in the join table. An example I had recently was a SortOrder field.
When querying with a materialized join table, it feels a little clumsy:
context.User.Select(user => new {
Name = user.Name,
Groups = user.GroupJoins
.OrderBy(groupJoin => groupJoin.SortOrder)
.Select(groupJoin => groupJoin.Group.Name)
});
Why you want refer to that junction table...?!
If you want to get Users of a group:
var users = from u in db.UserGroups.Include("User").Include("Group")
Where u.GroupID == gid
select u;
And simply vice versa if you need Groups of a User:
var groups = from g in db.UserGroups.Include("User").Include("Group")
Where g.UserID == uid
select g;

How to avoid duplicate userid in silverlight with wcf ria serivces

I am beginner and developing a silverlight navigation application using RIA services with SQL Server 2008.
I have a 'Registration' table where initially users request for membership are stored. The admins will verify them and later the particular user details are moved to 'Members' table from 'Registration'. Moreover when the term/period of membership comes to end the same details are finally moved to 'PastMembers' table from 'Members' table.
Now what I wanted is that before the registration details are submitted it should be checked in all three tables(Registration,Members,PastMembers) for username specified and if any record is found it should restrict user by submitting details to avoid duplicate userids.
I searched and tried to count the rows but even though I have a record with same userid I get count=0
Please let me know if any other better option or any rectification in this logic (please be a more brief since I am a beginner)
Checking in just first table
Code in submit button click handler
myDomainContext objctx1 = new myDomainContext();
var query1 = objctx1.GetregistrationsByIDQuery(userid_txtbx.Text);
objctx1.Load(query1);
var count = (from c in objctx1.registrations where c.userid == userid_txtbx.Text select c).Count();
// To see how many rows there
MessageBox.Show(count.ToString());
// Code for restricting details to be submitted
...............................
.....................
...............................
Function in myDomainService.cs
// Query to get usernames from registrations table
public IQueryable<registration> GetregistrationsByID(string id)
{
return this.ObjectContext.registrations.Where(s => s.userid == id);
}
consider sample fields in tables as:
Tables: Registration,Members,PastMembers having common columns as
userid,
fullname,
contact

Linq to SQL MVC issue with FK

right having a bit of a hard mental blog with some Linq to SQL and MVC.
Getting the basic MVC and L2SQL going ok.
FK relationships. -> when using MVC and we have a fk relationship in the model,
and the view is based on a strongly typed object - how do you get the data from the related table?
So for example
User (Table)
UserId
UserName
Call (Table)
CallId
UserId
CountryId
Country(Table)
CountryID
CountryName
SO I want to get only the calls for a user with a specific country?
The view - based on Call Object as this is the "Details" view -
how do i get a UserName and CountryName and still maintain a view based on Call?
It would seem that I still have to create an Object CallForUserByCountry - but this gets messy
on save as the CallForUserByCountry object also needs to implement how to create Call User and Country.
the linq query
var calls = from c in db.Call
where c.CountryID == id
select new CallForUserByCountry or new something// this is bit that suggests a new object.
Hopefully I missing something ...
If the Call data class has associations to User and Call data classes you can access Call's User and Country properties directly in your View. Also you can load data from related User and Country tables immediately (instead of lazy loading by default):
In Controller:
DataLoadOptions options = new DataLoadOptions();
options.LoadWith<Call>(x => x.User);
options.LoadWith<Call>(x => x.Country);
db.LoadOptions = options;
var calls = from c in db.Call
where c.Country.CountryName == countryName && c.User.UserName == userName
select c;
In View:
<%= Model.User.UserName %>
<%= Model.Country.CountryName %>
You could use the TempData bag and save the Username and CountryName there.
in the controller:
TempData["CountryName"] = countryName;
If I'm understanding this correctly you are trying to get calls from a specific user with a specific country. If that's the case, then as long as you have the relationships mapped in the Linq2SQL designer, then you should be able to access the user and country from the call as properties. So it would be something like:
var userName = call.User.UserName;
As I said, this is contingent on the relationships being mapped in the designer, otherwise Linq2SQL will have no indication that the two tables are related.
You could also have a separate query to just get the calls you need based on User and Country:
var calls = from c in db.Call
where c.User.UserID = userID
&& c.Country.CountryID == countryID
select c;
Your question can be taken two ways.
You want to display a list of calls using the current Call Details View. - This would need a new view. Unless the details view is a ViewUserControl. Then you could use PartialRender.
You want to add extra data to the current Details View - Add the extra data to the ViewData.
For number 2 you could do the following.
i prefer using joins for this, and I like working with objects detached from my DataContext. So normally i don't have the extra IQueryable in my objects.
I would still use the CallForUserByCountry object. Makes things verbose.
var calls = from call in db.Calls
join country in db.Countries on call.CountryId equals country.CountryID
join user in db.Users on call.UserId equals user.UserId
where user.UserName == userName && country.CountryName == countryName
select new CallForUserByCountry
{
UserName = user.UserName,
CountryName = country.CountryName,
Call = call
};
View["CallsForUserByCountry"] = calls.ToList();
In the view.
<% foreach(var callForUserByCountry in (IList<CallForUserByCountry>)ViewData["CallsForUserByCountry"]) { %>
.. Do stuff here .. I like using PartialRendering
<% Html.PartialRender("CallForUserByCountryDetail", callForUserByCountry); %>
<%}

Resources