I am having some trouble adding or removing relationships from an entity with AutoDetectChangesEnabled = false
set. Example models and code are as follows:
public class Category : Entity
{
public Guid CategoryId { get; set; }
public virtual ICollection<UserProfile> UserProfiles { get; set; }
public string Name { get; set; }
}
public class UserProfile : Entity
{
public Guid UserProfileId { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public string Name { get; set; }
}
var context = new OfContext();
context.Configuration.AutoDetectChangesEnabled = false;
var userProfile = context.UserProfiles
.Include(up => up.Categories)
.FirstOrDefault(up => up.UserProfileId == new Guid("XXXX"));
var category = context.Categories
.FirstOrDefault(c => c.CategoryId == new Guid("XXXX"));
userProfile.Categories.Add(category);
userProfile.Name = "Updated";
context.Entry(userProfile).State = EntityState.Modified;
context.SaveChanges();
The issue I am having is the addition of the category to the collection is not saved with SaveChanges
. If I have AutoDetectChangesEnabled = true
, this change is picked up and persisted. So I guess the real question is, how do I manually indicate that this collection has been modified.
I know that for properties, I can use the following
.Property(u => u.Name).IsModified
But I am not seeing anything similar to indicate a collection has been changed.
You can use context.ChangeTracker.DetectChanges()
to do it, EF will check if entries are changed, and the mark then to be persited in database, so you just mush change this method before SaveChanges
, se the code:
public class Category : Entity
{
public Guid CategoryId { get; set; }
public virtual ICollection<UserProfile> UserProfiles { get; set; }
public string Name { get; set; }
}
public class UserProfile : Entity
{
public Guid UserProfileId { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public string Name { get; set; }
}
var context = new OfContext();
context.Configuration.AutoDetectChangesEnabled = false;
var userProfile = context.UserProfiles.Include(up => up.Categories).FirstOrDefault(up => up.UserProfileId == new Guid("XXXX"));
var category = context.Categories.FirstOrDefault(c => c.CategoryId == new Guid("XXXX"));
userProfile.Categories.Add(category);
userProfile.FirstName = "Updated";
context.Entry(userProfile).State = EntityState.Modified;
context.ChangeTracker.DetectChanges();
context.SaveChanges();
In this case, you could also remove that line
context.Entry(userProfile).State = EntityState.Modified;
If you wont use DetectChanges method, you can use ObjectStateManager in this way
var context = new OfContext();
context.Configuration.AutoDetectChangesEnabled = false;
var userProfile = context.UserProfiles.Include(up => up.Categories).FirstOrDefault(up => up.UserProfileId == new Guid("XXXX"));
var category = context.Categories.FirstOrDefault(c => c.CategoryId == new Guid("XXXX"));
userProfile.Categories.Add(category);
userProfile.FirstName = "Updated";
var objectStateManager = ((IObjectContextAdapter)context).ObjectContext.ObjectStateManager;
objectStateManager.ChangeRelationshipState(userProfile, category, x => x.Categories, EntityState.Added);
objectStateManager.ChangeObjectState(userProfile, EntityState.Modified);
context.SaveChanges();
This line
objectStateManager.ChangeObjectState(userProfile, EntityState.Modified);
Will handle the modification of FirstName property, and any other simple property.
And this line
objectStateManager.ChangeRelationshipState(userProfile, category, x => x.Categories, EntityState.Added);
Will handle the relationship modification of Categories property.
The ChangeTracker
class doesn't hold all data about the state of your model. It contains only data about states of the entities but not about the state of independent associations such as many-to-many relationships (as mentioned in this answer )
These changes are tracked in the ObjectStateManager
class. You should be able to mark a relationship between two entities as changed with the ChangeRelationshipState
method (see official documentation )
Sidenote - to get the ObjectStateManager
for a DbContext
, it is necessary to cast the DbContext
to the ObjectContext
var objectStateManager =
((IObjectContextAdapter)dbcontext).ObjectContext.ObjectStateManager;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.