Let's say we neede to process a bunch of entities coming from an XML file, create EDM entites for each XML element and eventually persist them. Very trivial to accomplish using a little bit of LINQ.
- <Roles>
- <Role name="Admin"/>
- <Role name="Reader"/>
- <Role name="Writer"/>
- </Roles>
- var doc = XDocument.Load("Roles.xml");
- var roles = doc.Element("Roles").Elements("Role").Select(x => new Role { RoleName = (string)x.Attribute("name") });
- PermissionsAPIContext context = new PermissionsAPIContext();
-
- foreach (var role in roles)
- {
- context.AddToRoleSet(role);
- }
- context.Savechanges()
But wait, let's make this a little interesting...
- <Roles>
- <Role name="Admin"/>
- <Role name="Reader"/>
- <Role name="Writer"/>
- <Role name="Reader"/>
- </Roles>
See the problem now? If we process the above XML using the code from before, we end up adding the same entity twice!
So what do we do now?
ObjectStateManager to the rescue, let's rewrite the piece of code as follows:
- var doc = XDocument.Load("Roles.xml");
- var roles = doc.Element("Roles").Elements("Role").Select(x => (string)x.Attribute("name"));
- PermissionsAPIContext context = new PermissionsAPIContext();
- foreach (var role in roles)
- {
- Role roleEntity = GetRole(role, context);
- if (roleEntity.EntityState == EntityState.Added || roleEntity.EntityState == EntityState.Detached)
- {
- context.AddToRoleSet(roleEntity);
- }
- }
- context.SaveChanges();
-
-
- private static Role GetRole(string roleName,PermissionsAPIContext context)
- {
-
-
- var roleEntity = context.RoleSet.FirstOrDefault(r => r.RoleName.Trim().ToLower() == roleName.Trim().ToLower());
- if (roleEntity == null)
- {
- var stateEntries = context.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EtityState.Modified | EntityState.Unchanged);
- var roleEntityEntries = stateEntries.Select(s => s.Entity).OfType<Role>();
- roleEntity = roleEntityEntries.FirstOrDefault(r => r.RoleName.Trim().ToLower() == roleName.Trim().ToLower());
- if (roleEntity == null)
- {
- return new Role { RoleName = roleName };
- }
- }
- return roleEntity;
- }
A few of things note worthy here
1) In GetRoles() we first query the ObjectContext to check whether there is already a role present with the given name, if so we
simply return a reference to the existing entity instance
2) If the role is not existing then we check to see whether a role with the given name was added to the context, if so then we just
get a handle to this previously added(but not yet persisted) role and return that.
3) If the role is not existing and was not added previously then we create a new Role entity and return.
4) The caller checks whether the returned entity is an existing one and if not it's added to the ObjectContext.
After we are done processing all entities, we save all entities and we are done.
The above mechanism allows us to safely sidestep duplicates while processing based on some equality rule(which in this case happens to be the role name).
Hope this helps.