EF - how to add Relationship between 2 tables and insert refrenceId in the masterTable? - entity-framework

For example I have 3 tables:
Users -- the master table
{ Id, Name }
Permissions -- details
{ Id, PermissionTitle }
UserPermissions -- is a relation table between User and its Permissions
{ UserId , PermissionId}
I have 2 users in the tbUsers ( {1,"user1"} , {2,"user2"} )
and I have 3 permissions in the tbPermissions ( {1,"perm1"} , {2,"perm2"} , {3,"perm3"} )
now I want to add perm1 and perm2 to user1. What should I do in EF?
(I don't want to create/insert any Users or Permissions, I just want to add a relationship between them in the relation table)
because of EF, I don't have UserPermissions table in my dataModel.

If you want to load entities first you can do:
using (var context = new YourContext())
{
var user1 = context.Users.Single(u => u.Id == 1);
var perm1 = context.Permissions.Single(p => p.Id == 1);
var perm1 = context.Permissions.Single(p => p.Id == 2);
user1.Permissions.Add(perm1);
user1.Permissions.Add(perm2);
context.SaveChanges();
}
If you know Ids and you don't want to load entities first you can do:
using (var context = new YourContext())
{
var user1 = new User {Id = 1};
var perm1 = new Permission {Id = 1};
var perm1 = new Permission {Id = 2};
context.Users.Attach(user1);
context.Permissions.Attach(perm1);
context.Permissions.Attach(perm2);
user1.Permissions.Add(perm1);
user1.Permissions.Add(perm2);
context.SaveChanges();
}
These two approaches can be combined - for example you can load user from DB and create dummy objects only for permissions.

Users should have a navigation property Permissions so you need to add the permission to that collection. Should look similar to this:
user.Permissions.Add(permission1);
user.Permissions.Add(permission2);
context.SaveChanges();

Related

LINQ query for joining multiple tables and get comma separated values in single row

I have below tables with the values.
Account:
Id
Name
Email
101
Nasir Uddin
nasir#email.com
Role:
Id
Title
101
Admin
102
Operator
AccountRole:
AccountId
RoleId
101
101
101
102
Now I want to write a linq to have the result like below:
UserAccount
AccountId
Name
Email
Roles
101
Nasir Uddin
nasir#email.com
Admin, Operator
To get the above result I have written the below query in LINQ. But it does not get the expected result.
var userAccount1 = (from account in _db.Accounts
join accountRole in _db.AccountRoles on account.Id equals accountRole.AccountId
join role in _db.Roles on accountRole.RoleId equals role.Id
select new UserAccountInfo
{
AccountId = account.Id,
Name = account.UserFullName,
Email = account.Email,
Roles = string.Join(",", role.Title)
});
At last I found my answer. The results can be achieved in different ways. Examples are given below:
var answer1 = (from account in userAccounts
join accountRole in accountRoles on account.Id equals accountRole.AccountId
join role in roles on accountRole.RoleId equals role.Id
select new UserAccount
{
AccountId = account.Id,
Name = account.Name,
Email = account.Email,
Roles = role.Title
}).ToList().GroupBy(x => new { x.AccountId, x.Name, x.Email }).Select(y => new UserAccount
{
AccountId = y.Key.AccountId,
Name = y.Key.Name,
Email = y.Key.Email,
Roles = string.Join(", ", y.Select(a => a.Roles))
}).ToList();
----------------------------------------------------------------------------
var answer2 = (from account in userAccounts
join accountRole in accountRoles on account.Id equals accountRole.AccountId
join role in roles on accountRole.RoleId equals role.Id
group new { account, role } by new { account.Id, account.Name, account.Email } into ag
select new UserAccount
{
AccountId = ag.Key.Id,
Name = ag.Key.Name,
Email = ag.Key.Email,
Roles = string.Join(", ", ag.Select(x=> x.role.Title))
}).ToList();
----------------------------------------------------------------------------
var answer3 = (from account in userAccounts
let roles1 = from accountRole in accountRoles
join role in roles on accountRole.RoleId equals role.Id
where accountRole.AccountId == account.Id
select role
select new UserAccount
{
AccountId = account.Id,
Name = account.Name,
Email = account.Email,
Roles = string.Join(", ", roles1.Select(x => x.Title))
}).ToList();
The below gives you the expected result using Lambda Expression (not Query Expression) based on the information provided in your post (and some assumptions since I could not find e.g. UserFullName in any of your tables)
Note: I'm also convinced there is a more efficient way to do this, but it is a starting point if nothing else.
(Here is working .NET Fiddle of the below: https://dotnetfiddle.net/aGra15):
// Join the AccountRoles and Roles together and group all Titles for
// a given AccountId together
var groupedAccountRoles = AccountRoles.GroupJoin(Roles, i => i.RoleId, o => o.Id, (o, i) => new {o, i})
.Select(x => new {AccountId = x.o.AccountId, Titles = string.Join(",", x.i.Select(y => y.Title))});
// Perform another GroupJoin to group by AccountId and Join to groupedAccountRoles table. Then `string.Join()`
var userAccount1 = Accounts.GroupJoin(AccountRoles, acc => acc.Id, accrol => accrol.AccountId,
(o, i) => new {o, UserAccountRoles = i})
.GroupJoin(groupedAccountRoles, ii => ii.o.Id, oo => oo.AccountId,
(ii, oo) => new UserAccountInfo
{
AccountId = ii.o.Id,
Email = ii.o.Email,
Name = ii.o.Name,
Roles = string.Join(",", oo.Select(x => x.Titles))
});
This will give the following output:

How to delete or update using inner join in Entity Framework?

I need to delete some records using inner join in Entity Framework.
For example, I have User, Role and UserRoleMapping tables:
User => Id, Name
Role => Id, Name
UserRoleMapping => Id, UserId, RoleId
Now I need to delete the users who belong to role with Id = 2.
I need to fire the query as shown below
Delete user
from User
inner join UserRoleMapping on User.Id = UserRoleMapping.UserId
where UserRoleMapping.RoleId = 2
Is this is possible in Entity Framework?
In EF you need first load entities, select items and then DeleteObject . You need do it like:
using (var context = new YourContext())
{
var item = (from user in context.User
join userRoleMapping in context.UserRoleMapping on user.Id equals userRoleMapping.UserId
where userRoleMapping.RoleId == 2
select user).ToList().ForEach(context.User.DeleteObject);
context.SaveChanges();
}
Note:
ObjectContext.DeleteObject(entity) marks the entity as Deleted in the context. (It's EntityState is Deleted after that.) If you call SaveChanges afterwards EF sends a SQL DELETE statement to the database. If no referential constraints in the database are violated the entity will be deleted, otherwise an exception is thrown
or
using (var context = new YourContext())
{
var items = (from user in context.User
join userRoleMapping in context.UserRoleMapping on user.Id equals userRoleMapping.UserId
where userRoleMapping.RoleId == 2
select user).ToList();
foreach (var item in items)
{
context.Entry(item).State = EntityState.Deleted;
}
context.SaveChanges();
}
or using ExecuteStoreCommand, here you find more
using (var context = new YourContext())
{
context.ExecuteStoreCommand("DELETE FROM USER INNER JOIN USERROLEMAPPING ON USER.ID = USERROLEMAPPING.USERID WHERE USERROLEMAPPING .ROLEID = {0}", customId);
}

EF 6 - many-to-many - Join table without duplicates

I'm using EF6 have some confusion on seeding a many to many relationship.
I have the following:
A User has many saved ChartQueries (that they can execute to get a chart).
A ChartQuery typically belongs to only one user, but there are several "shared" ChartQuerys that every User can execute. As a result I set up a many to many relationship using a join table UserChartQuery. The tables are up in the database just fine at 1-to-many on each side of the join table.
However, I'm not quite understanding how to seed or use this relationship. I don't want to end up with several duplicates of the "shared" ChartQuerys (a duplicate for each User). Instead, there should only be a single row for each "shared" ChartQuery that is a part of each User's SavedChartQueries collection (along with other, non-shared ChartQuerys that belong to that User only).
It seems like I'm forced to duplicate for each user:
var sharedChartQuery = new ChartQuery { ... };
var nonSharedChartQuery = new ChartQuery { ... };
var userOneChartQueryOne = new UserChartQuery { User = userOne, ChartQuery = sharedChartQuery };
var userTwoChartQueryOne = new UserChartQuery { User = userTwo, ChartQuery = sharedChartQuery };
var userTwoChartQueryTwo = new UserChartQuery { User = userTwo, ChartQuery = nonSharedChartQuery };
context.UserChartQueries.Add(userOneChartQueryOne);
context.UserChartQueries.Add(userOneChartQueryTwo);
context.UserChartQueries.Add(userTwoChartQueryTwo);
So first of all is this the right way to seed (through UserChartQueries table directly) or should I seed each User's SavedChartQueries navigation property?
And will this result in duplicate sharedChartQuery in the join table for each User? If so is there any way to avoid this?
Ok I understand how this works now. The following works as expected:
var userOne = new User {};
var userTwo = new User {};
var chartQuery = new ChartQuery { };
context.Users.Add(userOne);
context.Users.Add(userTwo);
context.UserChartQueries.Add(new UserChartQuery { User = userOne, ChartQuery = chartQuery });
context.UserChartQueries.Add(new UserChartQuery { User = userTwo, ChartQuery = chartQuery });
context.ChartQueries.Add(chartQuery);
The last line adds it to the table where the record actually resides. Checking the join table in SSMS shows that it only holds the foreign keys and nothing else. There are no duplicates.

How to Add table association in Entity Framework?

I have a table called User, a table called Permission and an association table so Many Users can have many Permissions.
User
ID - PK
Permission
ID - PK
UserPermission
UserID - PK (FK to user)
PermissionID - PK (FK to Permission)
In entity framework how can I add an entry to the association table to link a user to a permission?
I have tried the following with no luck:
var user = _Repository.Users.Single(u => u.ID == someUserID);
var permission = _Repository.Permissions.Single(p => p.ID == somePermissionID);
user.Permissions.Add(permission) //Not working
user.Permission.Attach(permission) //Still not working
_Repository.Save();
Can anyone help?
It should be :
UserPermission obj = new UserPermission { UserID = someUserID, PermissionID = somePermissionID };
_Repository.UserPermissions.AddObject(obj)
_Repository.Save();
Hope this will help.

Entity framework many to many keeps adding extra record

I'm trying to add a new record to the link table using entityframework code first. What I have is a many to many on User and Role. The scenario I have is that when I'm changing a role for the user, I delete all their previous roles and add the new roles as follows:
//Delete all associated roles for user
var roleUser = db.Users.Include(r => r.Roles).FirstOrDefault(u => u.UserId == user.UserId);
var usersRoles = roleUser.Roles;
usersRoles.ForEach(role => roleUser.Roles.Remove(role));
//add the new roles
roleUser.Roles.AddRange(detachedUser.Roles);
db.SaveChanges();
So it removes them perfectly. But when adding new roles, it doesn't only add it to the link table but also the Role table. A completely new role gets added without a RoleName. user.Roles would contain an item with the following data:
RoleId;//1 <-- this Id exists in the database already but yet still it creates one instead of a linktable record.
RoleName;//null
How do I prevent EF from adding a whole new record and just add a record to the link table?
Update: I ended up doing this:
var roleUser = db.Users.Include(r => r.Roles).FirstOrDefault(u => u.UserId == user.UserId);
var roles = db.Roles;
foreach (var role in roles)
{
if (user.Roles.Any(r => r.RoleId == role.RoleId))
{
roleUser.Roles.Add(role);
}
else
{
roleUser.Roles.Remove(role);
}
}
db.SaveChanges();
try to save before adding new roles to the user
//Delete all associated roles for user
var roleUser = db.Users.Include(r => r.Roles).FirstOrDefault(u => u.UserId == user.UserId);
var usersRoles = roleUser.Roles;
usersRoles.ForEach(role => roleUser.Roles.Remove(role));
db.SaveChanges();
roleUser.Roles.AddRange(user.Roles); //add the new roles
db.SaveChanges();
Edit:
Have a look at this :
roleUser.Roles.AddRange(user.Roles); //add the new roles
where do user.Roles come from ?
I think the problem you have is that you need to attach your Roles before adding them to the user.
you also don't need to remove them all, simply remove those removed and then only add the new ones.
For each roll that you add you could try checking or setting the entity state. For example here I set the set to unchaged. This way it wont attempt to insert or update it.
myContext.Entry(roll).State = EntityState.Unchanged
More info here:
http://blogs.msdn.com/b/adonet/archive/2011/01/29/using-dbcontext-in-ef-feature-ctp5-part-4-add-attach-and-entity-states.aspx