I was trying to delete a record - but I'm getting this error:
The instance of entity type 'Users' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values
I tried the following ways, but all failed with the same error.
var Users = context.Users.Where(x => x.Id.Equals(UsersId));
context.Users.RemoveRange(Users);
await context.SaveChangesAsync();
var Users = await context.Users.AsNoTracking().FirstOrDefaultAsync(x => x.Id.Equals(UsersId));
context.Users.Remove(Users);
await context.SaveChangesAsync();
var Users = new Users() {Id = UsersId};
context.Users.Attach(Users);
context.Users.Remove(Users);
await context.SaveChangesAsync();
The presented code is not enought for understanding the root cause.
If it is a web application you might have issue with sharing same database context accross all http requests. But db context should be uniq for each http request. Avoid to make it singleton.
If it is a console application - you might have an issue with a configuration.
Option 1:
Try to do this:
Context.Entry(entity).State = EntityState.Detached
This is not a solution, but just for troubleshooting.
Option 2:
Try to do a very simple Console application with your database context and run your first code snippet - it should work.
Can be usefull:
instance of entity type cannot be tracked because another instance with same key value is tracked
Related
services.AddDbContextPool<SecurityDBContext>(options =>
options.UseSqlServer(GlobalConfig.Configuration["ConnectionStrings:DefaultConnection"],
b => b.UseQuerySplittingBehavior(QuerySplittingBehavior.SingleQuery))
);
This is how I added dbcontext,I used AddDbContextPool so the instance will be use over and over again for performance.
db.Entry(new AdminBlockClientConfig()
{
ActionId = input.aid.ToLongReturnZiro(),
MaxValue = input.value.ToIntReturnZiro(),
IsActive = input.isActive.ToBooleanReturnFalse(),
SiteSettingId = siteSettingId.ToIntReturnZiro()
}).State = EntityState.Added;
db.SaveChanges();
This is my code for adding new entity.
readonly SecurityDBContext db = null;
static List<AdminBlockClientConfig> AdminBlockClientConfigs = null;
public AdminBlockClientConfigService(SecurityDBContext db)
{
this.db = db;
}
This is my service constructor
services.AddScoped<IAdminBlockClientConfigService, AdminBlockClientConfigService>();
And this is my service injection config
The problem:
I don't have any validation for ActionId inside of my add new entity so if the user posts -1 for ActionId the entity will not be insert into SQL Server (relation problem) the system raises an exception and everything is as planed but the main problem is that one of the instance of SecurityDBContext become corrupted and I am no longer be able to call save change on that instance because the entity instance is still attached to dbcontext.
What is need:
It would be great if I can detach the entity after an error automatically so I can save the context.
I know how to detach entity from dbcontext, I need to its happen automatically (there is so many validation need to be added to project and I can not put time for those validation and if I put that time there will be high change of missing some place and its will be bug that can destroy my application and for performance I don't like to change the way I added dbcontext instance).
Thanks for your time.
edited: AddDbContextPool is not the problem, if one of my services add invalid data to dbcontext the other services can not use that dbcontext
How can I retrieve all users within a Service Principal with navigation properties such as Manager and properties such as Full name using Microsoft Graph API in as few as possible calls?
I'm using the Microsoft.Graph package and I've tried:
Attempt 1:
await graphClient.ServicePrincipals["objectId"].AppRoleAssignedTo.Request().GetAsync();
But this gives me only the Ids, which is 'okay' but then I would have to get all users separately, which would make for a lot of calls to the Graph API.
I could use the DirectoryObjects to get all users at once but that does not allow me to expand on the Manager property.
For example:
var users = await graphClient.DirectoryObjects.GetByIds(principals.Select(p => p.PrincipalId.ToString()), new string[1] { "User" }).Request().Expand("manager").PostAsync();
Gives me a error:
Could not find a property named 'manager' on type 'microsoft.graph.directoryObject'.
Attempt 2:
I've also tried to get the users by using a filter
await graphClient.Users.Request().Filter("appRoleAssignments/any(u:u/principalId eq objectId)").Expand(u => u.Manager).GetAsync();
But that gives me a error:
Request_UnsupportedQuery
You can write the code like this:
var user = await graphClient.Users.Request().Filter("id in ('{objectId1}', '{objectId2}', ..., '{objectIdn}')").Expand(u => u.Manager).Select("displayName").GetAsync();
Ideally, this will use just one call to return the data you need.
BUT based on the requirement "in as few as possible calls", we will have to face a problem, that is, we need to put all the object ids into the request, which may cause the request to be too long and eventually fail.
I didn't test this scene and it's just a direction which may be helpful.
I still recommend that you use loop to get the information.
I am using ASP.NET Entity Framework and I am trying to update a single column with the following code:
[HttpGet]
public void MarkOffline(string online)
{
Users user = new Users { email = online, isOnline = false };
db.Entry(user).Property("isOnline").IsModified = true;
db.SaveChanges();
}
But I get this error:
Member 'IsModified' cannot be called for property 'isOnline' because
the entity of type 'Users' does not exist in the context. To add an
entity to the context call the Add or Attach method of DbSet<Users>.
The part I don't know how to do:
To add an entity to the context call the Add or Attach method of
DbSet<Users>.
How do I fix my problem?
If you want to update like this, you'll need to Attach the entity where the entity has its primary key set.
Given you don't have its primary key but only one of its (unique, hopefully) fields, you need to query the record first and then update it:
var existing = db.Users.FirstOrDefault(u => u.email == email);
existing.IsOnline = true;
db.SaveChanges();
That being said, this is not how you record a user's online status in a web application. You rather update a user's LastAction timestamp with each action they perform, and mark a user as offline at runtime when their LastAction is more than N seconds or minutes ago.
While looking for a way to be able to assign and revoke roles via an admin controller for users other than the one making a request, I've implemented a custom IAuthorizeFilter that checks if Guid tag, stored as a Claim, matches to a value in the Entity Framework 7 Code First Identity table for UserClaims.
Essentials, it's this code:
public class RefreshUserClaimsFilterAttribute : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext context)
{
var User = context.HttpContext.User;
var dbContext = context.HttpContext.ApplicationServices.GetRequiredService<ApplicationDbContext>();
var stampFromClaims = User.Claims.FirstOrDefault(Claim => Claim.Type == "ClaimsStamp")?.Value;
var stampFromDb = dbContext.UserClaims.Where(UserClaim => UserClaim.UserId == User.GetUserId()).ToList().FirstOrDefault(UserClaim => UserClaim.ClaimType == "ClaimsStamp")?.ClaimValue;
// Update claims via RefreshSignIn if necessary
}
}
I'm having the problem at the line where I'm assigning var stampFromDb, it could be much more readable in the following way:
var stampFromDb = dbContext.UserClaims.FirstOrDefault(UserClaim => UserClaim.UserId == User.GetUserId() && UserClaim.ClaimType == "ClaimsStamp")?.ClaimValue;
That, however, gives me cached (the same values as the actual claims from User.Identity) results and I could not find any documentation on this. My best guess is that the error is somewhere on my side, but I've never encountered such a problem before. This is the first time I'm using Asp.Net 5 and EF7. I'm using the default connection (LocalDB) to SQL Server 12.0.2000.
Is this a feature and, if yes, can it be turned off or did I make a mistake somewhere?
The issue was caused due to there being two different ways to create a service via dependency injection:
The sample code in my question used
var dbContext = context.HttpContext.ApplicationServices.GetRequiredService<ApplicationDbContext>();
where it should use
var dbContext = context.HttpContext.RequestServices.GetRequiredService<ApplicationDbContext>();
The difference here is between ApplicationServices and RequestServices. It looks like the ApplicationServices injector does have an instance of the database context somewhere which has had the DbSet filled earlier and therefore returning cached data instead of doing a database query.
I have been dealing with this for days
Summary
I am creating a Social site that will be the back bone for another web application. The hangup is when I submit a request to create a group all goes well, but if I attempt to submit this form again with different data I get a DbEntityValidationException. The exception is related to the ApplicationUser entry.
Details
When I start the Application in Debug mode and submit the Group creation form for the first time it will succeed, adding all the entities into the database as excepted. I have verified this and all looks good. While in the same Debug session, I change the information in the form, to create another group, and submit the form, which leads to the DbEntityValidationException.
The error is related the when I try to insert a SocialGroupMemberModel which contains a reference to the User, and other details related to the users status in the group. The User entry is being marked as added and EntityFramework is trying to insert the User instead of updating. I have attempted to set the Navigation (User) and set the ForeignKey (UserId), both lead to the same error.
I am using HttpContext.Current.GetOwinContext().Get<ApplicationDbContext>();
In the Controller I use ApplicationUserManager to get the User Entity, I then pass this to the Repository to create the group (in either case, either passing the ID, or Entity itself, doesn't work the second time)
Group Creation Code:
var groupInfo = new SocialGroupInfo
{
Created = DateTime.Now,
Description = model.Description,
ShortDescription = model.ShortDescription,
Name = model.Name,
Tags = TagRepo.GetTags(),
Members = new List<SocialGroupMember>()// { member }
};
var groupModel = new SocialGroupModel
{
Slug = model.Slug,
Info = groupInfo
};
Context.SocialGroups.Add(groupModel);
var member = new SocialGroupOwnerModel
{
Joined = DateTime.Now,
UserId = creator
//User = null
//Group = groupInfo
};
groupInfo.Members.Add(member);
//creator.SocialGroups.Add(member);
SaveChanges();
The Validation Error is: "User name ** is already taken" so this leads me to believe that on the second attempt to add the new group, it is attempting to add a new user.
Please ask for any additional information needed, thanks.
This issue was caused by the IoC holding a reference to the previous DbContext, unsure as to why, but removing all usage of Autofac fixed the issue.
Very anticlimactic solution, but issue fixed...
Now the issue is to figure out why Autofac was behaving this way, all Debugging showed that the classes were created each request... but that is another question.