Insert/Update data to Many to Many Entity Framework . How do I do it? - entity-framework

My context is =>
Using this model via Entity Framework code 1st,
data table in database becomes =>
1) User Table
2) Role Table
3) UserRole Table - A new linked table created automatically
Model for User is =>
Model for Role is =>
and my O Data query for inserting record for single User/Role table working properly
Now, what query should I write, when I want to Insert record to UserRole table
can someone have any idea

// Fetch the user.
var user = await metadataManagentClient.For<User>().FirstOrDefaultAsync(x => x.Name == "Test");
// If you want to add a new role.
var newRole = new Role()
{
Name = "My new role"
};
user.Roles.Add(newRole); // Adds new role to user.
// If you want to add an existing role
var existingRole = await metadataManagentClient.For<Role>().FirstOrDefaultAsync(x => x.Name == "My Existing Role");
user.Roles.Add(existingRole); // Adds existing role to user.
// Save changes.
metadataManagentClient.SaveChanges();
Or
await metadataManagentClient.SaveChangesAsync();
You might want to set ID as well. But watch out for new Guid() since it generates an empty guid. What you probably want (if you're not using IDENTITY) is Guid.NewGuid().

Related

How to update only one column value in database using Entity Framework?

I have a table with columns username, password. Data can be updated by admin for the table.
Now I want to add a new column named IsAgree (as a flag), it need to set when user logs in for the first time. But while setting data, it should not affect other column data, I will only send usename and Isagree flag as an object.
flgDetail = { usename:"vis" Isallowed:True }
[Route("api/TermsAndCondition/setflag")]
public IHttpActionResult post(FlagDetails FlagDetail)
{
var user = _context.table.Where(s => s.UserName == flagDetail.UserName);
}
Should I use post or put?
How can I update only one column?
And it should not affect other columns.
you can use either post or put.It's not a problem.You can update it as shown below.
[Route("api/TermsAndCondition/setflag")]
public IHttpActionResult post(FlagDetails flagDetail)
{
var user = _context.table.Where(s => s.UserName == flagDetail.UserName);
user.IsAgree =flagDetail.Isallowed;
_context.SaveChanges()
}

Query regarding trigger?

I am having following requirement:
1) To get list of all the users for whome profile has been changed.
2) Then query on FRUP (It is a custom object) to retrieve all the records which are associated with the user whose profile is changed.(FRUP object will contain the list of all the records created by all the users on all the objects say Account, Opportunity)
3) Update FRUP.
For achieving this I wrote one trigger through which i am able to fetch list of all the users whose profile has changed which is as follows:
Trigger UserProfileTrigger on User (before update) {
List<User> usr = new List<User>();
Map<String,String> userMap = new Map<String,String>();
for(User u: Trigger.new){
//Create an old and new map so that we can compare values
User oldOpp = Trigger.oldMap.get(u.ID);
User newOpp = Trigger.newMap.get(u.ID);
//Retrieve the old and new profile
string oldProfileId = oldOpp.profileId;
string newProfileId = newOpp.profileId;
//If the fields are different, the profile has changed
if(oldProfileId != newProfileId){
System.debug('Old:'+oldProfileId);
System.debug('New :'+newProfileId);
usr.add(u);
System.debug('User :'+usr);
}
}
}
Also Following are the fields on custom object FRUP:
1)Owner
2)Name
3)Record ID
4)Folder ID
5)Created By
6)Last Modified By
any help/suggestions??
I'm not sure what field on the FRUP references the user Id it relates to, but you can loop through the FRUP object with something like this:
List<FRUP> frupToUpdate = new List<FRUP>();
for (FRUP f : [
Select
OwnerId,
Name, //etc.
UserId //the field that references the user Id
from FRUP
where userId = : usr]) {
//update field on FRUP, e.g. f.Name = 'New Name';
frupToUpdate.add(f);
}
This selects the FRUP records that relate to the users with changed profiles. It then updates a field on the record and adds the record to a list for updating. Note that this should be after your loop for(User u: Trigger.new). Then update the FRUP records that have changed:
update frupToUpdate;

Entity Framework Insert, Update, Delete During Same Transaction

I have a problem, I have a wizard that can update data AND insert data. So, if I have an existing list of team members, I can update their roles but If necessary, I can also add/insert a person to this team. So I can update roles and insert a new team member into the same table all during the same transaction. Data can be updated to and inserted to table teamMembers.
When I try to add a new teamMember, I also have an existing member where I simply want to update his role.
Both changes happen to the same table called TeamMember. When I debug the context, everything looks good. it shows that there are two changes that will occur for the TeamMember table. One transaction is the update and the other transaction is the insert. When I perform an update using:
var teamMember = new TeamMember
{
Name = user.FullName,
UserProfileId = user.UserProfileId,
RoleId = user.RoleId
};
TeamMemberList.Add(teamMember);
project.TeamMembers = TeamMemberList;
//And then call
this.Context.Projects.Attach(project);
this.Context.Entry(project).State = System.Data.EntityState.Modified;
it updates but the record that needs to be inserted fails.
HOW CAN I DO BOTH AN INSERT AND UPDATE TO THE SAME TABLE DURING THE SAME TRANSACTION?
CURRENT ERROR IS:
The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: A referential integrity constraint violation occurred: The property values that define the referential constraints are not consistent between principal and dependent objects in the relationship.
I think you need to add the TeamMember entity to the context's global list. Something like:
var teamMember = new TeamMember()
{
Name = user.FullName,
UserProfileId = user.UserProfileId,
RoleId = user.RoleId
}
project.TeamMembers.Add( teamMember );
this.Context.TeamMembers.Add( teamMember );
this.Context.SaveChanges();
How about loading the existing project entity first and then adding members.
var project = this.Context.Project.Where(p => p.ID = "bar").Include("TeamMembers").FirstOrDefault();
var teamMember= new TeamMember
{
Name = user.FullName,
UserProfileId = user.UserProfileId,
RoleId = user.RoleId
};
project.TeamMembers.Add(teamMember);
this.Context.SaveChanges()

Many-to-Many Inserts with Entity Framework

Say I have two entities with about 20 properties per entity and a Many-to-Many relationship like so:
User (Id int,Name string, .......)
Issue (Id int,Name string, .......)
IssueAssignment (UserId,RoleId)
I want to create a new Issue and assign it to a number of existing Users. If I have code like so:
foreach(var userId in existingUserIds)
{
int id = userId
var user = _db.Users.First(r => r.Id == id);
issue.AssignedUsers.add(user);
}
_db.Users.AddObject(user);
_db.SaveChanges();
I noticed it seems terrribly inefficient when I run it against my SQL Database. If I look at
the SQL Profiler it's doing the following:
SELECT TOP(1) * FROM User WHERE UserId = userId
SELECT * FROM IssueAssignment ON User.Id = userId
INSERT INTO User ....
INSERT INTO IssueAssignment
My questions are:
(a) why do (1) and (2) have to happen at all?
(b) Both (1) and (2) bring back all fields do I need to do a object projection to limit the
fields, seems like unnecessary work too.
Thanks for the help
I have some possible clues for you:
This is how EF behaves. _db.Users is actaully a query and calling First on the query means executing the query in database.
I guess you are using EFv4 with T4 template and lazy loading is turned on. T4 templates create 'clever' objects which are able to fixup their navigation properties so once you add a User to an Issue it internally triggers fixup and tries to add the Issue to the User as well. This in turns triggers lazy loading of all issues related to the user.
So the trick is using dummy objects instead of real user. You know the id and you only want to create realtion between new issue and existing user. Try this (works with EFv4+ and POCOs):
foreach(var userId in existingUserIds)
{
var user = new User { Id = userId };
var _db.Users.Attach(user); // User with this Id mustn't be already loaded
issue.AssignedUsers.Add(user);
}
context.Issues.AddObject(issue);
context.SaveChanges();

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