'How to use the Entity Framework `ValueComparer<T>`?

I'm working on a ASP.NET 3.1 project. The class EmployeeSummary contains a public property string[] Roles

public string[] Roles { get; set; }

and has the value converter set for the array of strings:

          modelBuilder.Entity<EmployeeSummary>()
                .Property(e => e.Roles)
                .HasConversion(v => string.Join(",", v),
                    v => v.Split(new[]
                        {
                            ","
                        }, StringSplitOptions.RemoveEmptyEntries)
                        .ToList()
                        .Distinct(StringComparer.OrdinalIgnoreCase)
                        .ToArray());

I'm getting the followingSystem.InvalidOperationException indicating that I have no value comparer set:

The property 'Roles' on entity type 'EmployeeSummary' is a collection or enumeration type 
with a value converter but with no value comparer. 
Set a value comparer to ensure the collection/enumeration elements are compared correctly.

My approach was to add (likewise to the examples in the Microsoft documentation)

  • A var valueComparer in class EmployeeSummary
  • Set to new ValueComparer<string[]> instead of new ValueComparer<List<int>>
  • Check if two arrays are identical. This however doesn't work:
        public string[] Roles { get; set; }

        private var valueComparer = new ValueComparer<string[]>(
             (c1, c2) => c1.SequenceEqual(c2));

with a message that the constructor cannot be resolved. Is this the right way to go, or how can I solve this error message?



Solution 1:[1]

You need to set the ValueComparer in the method HasConversion.

A working example for this would be:

            modelBuilder.Entity<EmployeeSummary>()
            .Property(e => e.Roles)
            .HasConversion(
                v => string.Join(',', v),
                v => v.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList()
                    .Distinct(StringComparer.OrdinalIgnoreCase)
                    .ToArray(), new ValueComparer<ICollection<string>>(
                    (c1, c2) => c1.SequenceEqual(c2),
                    c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())),
                    c => c.ToList()));

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 shocks