Entity Framework: Working with FK's (why do they get hidden?) - asp.net

First of all, let's define a few tables:
Users table will store information about a user:
Users
- UserID (int, PK)
- ...
UserTasks is a table that stores a task associated with a user:
UserTasks
- userID (int, FK to Users table)
- taskName (varchar)
When I generate the UserTasks table using the ADO Entity Framework, I'll get a class that looks like this:
UserTasks
- taskName (string)
- Users (collection of Users objects)
Note: There's no userID that is generated in the UserTasks table. So let's assume now that I need to insert a new user task... how do I do it? I don't have access to the userID FK field, so my only option is to do a lookup and populate a Users object, then pass that to my task object, like this:
//get the user we are interested in
var user = (from u in context.Users
where u.userID == 2
select u).FirstOrDefault();
//create the new task
UserTasks newTask = new UserTasks();
newTask.taskName = "New Task";
newTask.User = user;
The problem with the above is that I'm doing an extra and needless database call to populate my user object. Is there anyway to somehow create a new mapping to my userID field and still keep the User object?
Thanks
--Ryan

Not now, but maybe in the next version.

Related

How to use Linq where condition to check if a list of strings contains any string

I have a LINQ query like this:
var data = from user in _context.Users
select new
{
UserId = user.Id,
Username = user.UserName,
RoleNames = (from userRole in _context.UserRoles
join role in _context.Roles on userRole.RoleId
equals role.Id
where userRole.UserId == user.Id
select role.Name).ToList()
};
if (!string.IsNullOrEmpty(searchText))
data = data.Where(x => x.Username.Contains(searchText) || x.RoleNames.Any(r => r.Contains(searchText)));
The result are something like this:
User Id | Username | RoleNames
1 | Matt | [User, Admin]
2 | Jennifer | [User]
3 | John | []
But the
x.RoleNames.Any(r => r.Contains(searchText))
is not working, it's causing InvalidOperationException: The LINQ expression '...' could not be translated.
I want to pass in a searchText to search for either "Username" and "RoleNames" columns.
E.g. if I pass in searchText = 'Jen' it will return User Id 2, and if I pass in searchText = 'user' it will return User Id 1 and 2.
Any help would be appreciated.
While theoretically it is possible to translate this condition to the SQL, your EF Core version do not supports that. Consider to make filter before defining custom projection:
var users = _context.Users.AsQueryable();
if (!string.IsNullOrEmpty(searchText))
users = users.Where(x => x.Username.Contains(searchText) || x.Roles.Any(r => r.Contains(searchText)));
var data =
from user in users
select new
{
UserId = user.Id,
Username = user.UserName,
RoleNames = (from userRole in _context.UserRoles
join role in _context.Roles on userRole.RoleId
equals role.Id
where userRole.UserId == user.Id
select role.Name).ToList()
};
This may not be the answer you want now but you'll probably look back on this and see it as the right answer later.
Your ORM (Probably Entity Framework) can't translate your Linq Expressions into a query. If your project will have a small database and you don't need your queries to perform well then, tweak your expression so that the ORM can generate a functioning, albeit sub-optimal, query.
If data will be a significant part of your project then switch to a light ORM like Dapper and learn the query language of your database. Write optimal, parameterised queries in that query language and yield the long term benefits.

filtering records in Controller index action

I am trying to add a condition to an index action to only get certain records. The story goes like this.
The registered user has an identities role of either Owner or ServiceCompany
There is an Owner table and a Service Companies table, each has a RegUserID which holds the UserID from the Identities table based on the role of that user.
There is an Asset table (which is to be indexed) which has an OwnerID and a Service CompanyID field.
Based on the UserID of the logged in user I need to identify the users role, then get the OwnerID or Service CompanyID from the relevant table using the RegUserID then based on the role list the assets with OwnerID or Service CompanyID
I have got as far as...
// GET: Assets
public ActionResult Index()
{
if(Roles.GetRolesForUser().Contains("Owner") == true)
{
// Get OwnerID from Owners table where Owners.RegUserID == User.Identity.GetUserId();
// Get list of assets from Asstes where Assets.OwnerID == OwnerID
}
else if(Roles.GetRolesForUser().Contains("Service Company") == true)
{
// Get ServiceCompanyID from Owners table where ServiceCompanies.RegUserID == User.Identity.GetUserId();
// Get list if assets from Assets where Asstes.ServiceCompanyID == ServiceCompanyID
}
return View(assets);
}
I am totally stuck on how to get the OwnerID or ServiceCompanyID then the list of assets to return to the view.
Not sure on your database setup etc.. But based on your question you should be able to to this without worrying what "Role" the user is in with a Linq Query similar to the following
var userId = User.Identity.GetUserId();
var asset = from a in context.Assets
join o in context.Owners on a.OwnerId equals o.OwnerId into oa
from asst in oa.DefaultIfEmpty()
join s in context.ServiceCompanies on a.ServiceCompanyId equals s.ServiceCompanyId into sa
from service in sa.DefaultIfEmpty()
where asst.RegUserId == userId || service.RegUserId == userId
select a;
return View(asset);

ASP membership or facebook membership (working with db and process)

I want to ask you for something:
I want do an IS on asp.net (MVC) with my custom membership connected to MSSQL
On DB will be more things and there will be a lot of connection with "userId"
But it's not a necessary to create NEW account just for this IS (but you can)...
But if you choose that you don't want create new account you can join with your FB.
But there is a problem... How create a design and working with my DB when you are just FB user and you want make some change (add some data to DB... And this data are connected to your account but it can be IS-account or FB, and of course I want to add users to roles, and with the FB? It's possible?)
Here is my part of DB which is responsible for memberships:
User:
id ( uniqueidentifier PK)
username (text)
password..
....
Role:
id ( uniqueidentifier PK)
name ( text)
UsersInRoles:
id ( uniqueidentifier)
roleID (uniqueidentifier (FK from Role) )
userID (uniqueidentifier (FK from User) )
And I am using an ID (PK from User table everywhere (in other tables) as signatures who add a new item and other)
Thank you.

associating my own table to userProfile table in SqlMembership doesn't work as expected

I have this table named Person :
FirstName,LastName,BirthDate,UserId(FK,int,not null)
userId field is joint to userProfile table of SqlMembership
and 2 other tables named Category and News besides SqlMembership tables like UserInRole,... in a database
I create a .edmx file and add my own tables (Category,News,Person) to it.cause my approach is database first.
now I except when I get current logged in user,I can access it's related person:
if (Request.IsAuthenticated)
{
var context = new UsersContext();
var user = context.UserProfiles.SingleOrDefault(u => u.UserName == "asma");
ViewBag.fullName= user.person.FirstName+' '+user.person.LastName; //ERROR
}
but when I write user. the intellisense just gives me 2 fields:UserId and UserName
where is user.person....
on the other hand I cannot add UserProfile to my .edmx file.adding UserProfile to .edmx file causes 'MVC4 duplicated UserProfile table' problem
What's my fault?adding my own tables to the database that is created by SqlMembership?

Get the UserID of the current logged in User in asp.net default membership provider

I have two tables
Employee (EmpID, Name, UpdatedBy, UpdateDate)
EmpContact (ContactID, Contact,EmpID)
I am trying to create a trigger which update a Employee table fields UpdatedBy,UpdateDate. when contact is added or modified i want to update Employee's UpdatedBy and UpdateDate fields (These two tables have different asp.net-mvc views).
I am using default membership provider to authenticate the user. So my question is how can i get the current logged in user in trigger who initiated the insert, update or delete. Is there any way i can know which asp.net user id initiated the transaction within the TRIGGER
Create an insert/update/delete trigger that updates the Emplyoee table when records in EmpContact are created/updated/deleted, for example(insert):
CREATE TRIGGER [dbo].[trgCreateEmpContact] ON [dbo].[EmpContact]
FOR INSERT
AS
UPDATE dbo.Employee
SET UpdateDate=GetDate(), UpdatedBy = I.UpdatedBy
FROM Employee E
INNER JOIN Inserted I ON E.EmpID = I.EmpID
So you need to add the UpdatedBy column to your EmpContact table too.
You get the current logged in user in the following way:
MembershipUser currentUser = Membership.GetUser();
GUID currentUserID = (GUID)currentUser.ProviderUserKey;
Another(better) approach would be to create a stored-procedure that internally creates the EmpContact record and updates the Employee table in a transaction, for example(untested):
CREATE PROCEDURE [dbo].[InsertEmpContact]
#ContactID int OUTPUT,
#Contact varchar(50) OUTPUT,
#EmpID int OUTPUT,
#UpdateDate datetime OUTPUT,
#UpdatedBy int OUTPUT,
with execute as Owner
AS
BEGIN TRANSACTION
INSERT INTO EmpContact(Contact, EmpID)
VALUES (#Contact,#EmpID)
;SELECT #ContactID=ContactID,#Contact=Contact,#EmpID=EmpID,#UpdateDate=GetDate()
FROM EmpContact WHERE (ContactID = SCOPE_IDENTITY())
;UPDATE dbo.Employee
SET UpdateDate=#UpdateDate, UpdatedBy = #UpdatedBy
WHERE EmpID = #EmpID
IF ##ERROR <> 0
BEGIN
-- Rollback the transaction
ROLLBACK
RETURN
END
COMMIT
If you want to detect the current logged in user from memebership please use these links
http://www.codeproject.com/KB/aspnet/CustomMembershipProviders.aspx
http://theintegrity.co.uk/2010/11/asp-net-mvc-2-custom-membership-provider-tutorial-part-2/
It depends on how your app connects to your database. If you do it, like almost all of us, with connection pooling and a single user connecting to the database, the answer is no, you cannot know that in the trigger.
E.g. the app connects to the database as sa/pwd (not advisable, but for arguments sake only).
If user one (Paul) connects to the db and does an update, your trigger will get sa as user.
If user two (Anne) connects to the db, the trigger will also get sa as user.
So you need to include the update of the user in the update statmement (or as an argument to your stored procedure)

Resources