Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework Many-to-Many Self Relationship and Optimistic Concurrency Control

I have an entity that has a Many-to-Many self-relationship. As an example consider this entity:

public class User
{
    public int ID { get; set; }
    public string UserName { get; set; }

    public virtual ICollection<User> Friends { get; set; }
}

Here is how I configure the mapping:

HasMany(t => t.Friends).WithMany()
    .Map(m => { 
        m.MapLeftKey("UserID");
        m.MapRightKey("FriendID");
        m.ToTable("UserFriends");
        });

As this relationship is now managed by the EF, I don't really have access to the UserFriends DbSet in my code and cannot handle the concurrent access to it. In order for this composition to handle concurrent access(add/remove), do I need to handle the Many-to-Many relationship myself and then add a [Timestamp] column or is there a way to tell EF to handle this concurrently itself? Like a configuration in the model builder.

Edit: I'm using EF 6 and currently if there is a concurrent operation on the entity(e.g trying to remove a friend that currently doesn't exits on the database) I get the following error message and an DbUpdateException:

An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for details.

like image 732
Farhad Alizadeh Noori Avatar asked Apr 22 '15 16:04

Farhad Alizadeh Noori


People also ask

How does Entity Framework handle many-to-many relationships?

The many-to-may relationship can be achieved using HasMany and WithMany methods. The default conventions for many-to-many relationships creates a joining table with the default naming conventions. You can customize a joining table name and column names using Fluent API.

How do you configure entity framework for optimistic concurrency?

If you do want to implement this approach to concurrency, you have to mark all non-primary-key properties in the entity you want to track concurrency for by adding the ConcurrencyCheck attribute to them. That change enables the Entity Framework to include all columns in the SQL WHERE clause of UPDATE statements.

How do I resolve DbUpdateConcurrencyException?

Custom resolution of optimistic concurrency exceptions SaveChanges(); } catch (DbUpdateConcurrencyException ex) { saveFailed = true; // Get the current entity values and the values in the database var entry = ex. Entries. Single(); var currentValues = entry. CurrentValues; var databaseValues = entry.


1 Answers

Optimistic concurrency does not apply here.

A junction table is never updated. Its records are either added or deleted. This means that there are no CRUD operations that need a rowversion.

So in fact, concurrency is fairly easy:

  • Two concurrent users can't add the same association, because the last one will bump into a unique key violation.
  • Two concurrent users can't delete the same association, because the last one will see an exception that an unexpected number of records (0) was affected.
  • As for foreign key problems (adding/removing an association to an entity that was deleted in the mean time). These will also raise exceptions.

So it boils down to handling exceptions and translating them to comprehensible user feedback. All these situations must also be dealt with in situations where updates (and optimistic concurrency) do play a role.

like image 176
Gert Arnold Avatar answered Oct 02 '22 18:10

Gert Arnold