1

Some of the entities in my application have 4 audit properties on them:

    public virtual DateTime WhenAdded { get; set; }

    public virtual DateTime? WhenUpdated { get; set; }

    public virtual User AddedBy { get; set; }

    public virtual User UpdatedBy { get; set; }

I am using a code first approach and have the following extension method to map the user properties:

    public static void MapAuditFields<T>(this EntityTypeConfiguration<T> configuration) where T : class, IAuditable
    {
        configuration.HasOptional<User>(e => e.AddedBy)
            .WithOptionalDependent()
            .Map(a => a.MapKey("AddedByUserId"));
        configuration.HasOptional<User>(e => e.UpdatedBy)
            .WithOptionalDependent()
            .Map(a => a.MapKey("UpdatedByUserId"));
    }

This is working fine in most cases, but not on the User class, which of course has a recursive relationship with itself. I have seen various posts on the internet suggesting that entity framework has a bug when you try to customise join table column names in this scenario, for example:

Self-referencing many-to-many recursive relationship code first Entity Framework

and

http://social.msdn.microsoft.com/Forums/en-US/f058097d-a0e7-4393-98ef-3b13ab5b165d/code-first-sequence-contains-more-than-one-matching-element-exception-when-generating-schema?forum=adonetefx

The error I am getting is "Sequence contains more than one matching element".

Does anyone know if this has been fixed in entity framework 6?

Many thanks.

Community
  • 1
  • 1
gusgorman
  • 170
  • 1
  • 11

1 Answers1

2

Use WithMany() instead of WithOptionalDependent() as a user can add or update multiple other users

Class:

public class User
{
    public int Id { get; set; }
    public virtual User AddedBy { get; set; }

    public virtual User UpdatedBy { get; set; }
}

Fluent API calls:

        modelBuilder.Entity<User>()
            .HasOptional( u => u.AddedBy )
            .WithMany()
            .Map( fkamc => fkamc.MapKey( "AddedByUserId" ) );

        modelBuilder.Entity<User>()
            .HasOptional( u => u.UpdatedBy )
            .WithMany()
            .Map( fkamc => fkamc.MapKey( "UpdatedByUserId" ) );

Results:

results

Moho
  • 15,457
  • 1
  • 30
  • 31
  • Many thanks for the answer but unfortunately this gives the same error. – gusgorman Feb 19 '14 at 11:18
  • ok, hmm, strange. Could you please share how you are mapping the audit fields on your other entities? – gusgorman Feb 19 '14 at 13:14
  • I just threw this together as a demo; I don't have other entities for this – Moho Feb 19 '14 at 13:16
  • I'm getting very strange behaviour here. This is the start of the project so I have only got 2 entities, User and Address. I have just removed the audit columns from Address, and still can't get your solution to work, but my original mapping works. When I re-add the audit columns to Address I then get the original error again. – gusgorman Feb 19 '14 at 16:14
  • I am now thinking that this is nothing to do with the recursive relationship. The ""Sequence contains more than one matching element" error is thrown whenever I map 2 entities with audit columns using the mapping code I have already posted. Thankyou for your help. I'm guessing I should probably start a different thread. – gusgorman Feb 20 '14 at 08:54
  • You should still use `.WithMany()` in those scenarios as well – Moho Feb 20 '14 at 12:38
  • Ok great. Have revisited this and changed all similar mappings throughout the model to use .WithMany() and now it works. If you are ever in Bristol England I owe you a drink :) I have to admit I don't find this api very intuitive. For .WithMany() to suddenly refer to the other side of the relationship seems a bit weird to me but maybe thats just because I am used to hibernate. Anyway, thankyou! – gusgorman Feb 20 '14 at 15:25