Reputation: 332
I use ValueConverter to map custom property type (List) to string. The conversion works perfectly, but I cannot set the EntityState to modified, because EF does not find the entity.
When I modify the list, EF does not detect changes, which is exptected. However, when I try to change the state manually, I get error
The entity type 'List<List<Reward>>' was not found. Ensure that the entity type has been added to the model.
Only workaround I have found is to set the property to clone of the list, which is not ideal.
model.PropertyName = new List<Reward>(model.PropertyName); // clone the list
Here is some sample code:
public class RewardContainer
{
public List<List<Reward>> Rewards { get; set; }
}
// db context
protected override void OnModelCreating(ModelBuilder builder)
{
// use custom conversion, which is working fine
builder.Entity<RewardContainer>().Property(p => p.Rewards).HasConversion(ValueConverters.GetJsonConverter<List<List<Reward>>>());
}
// controller
public async Task ModifyProperty()
{
rewardContainer.Rewards[0].Add(someReward);
// try to manually change the EntityState...
dbContext.Entry(rewardContainer.Rewards).State = EntityState.Modified;
// error: The entity type 'List<List<Reward>>' was not found. Ensure that the entity type has been added to the model.
await dbContext.SaveChangesAsync();
}
Upvotes: 1
Views: 1084
Reputation: 332
Using a ValueComprarer in addition to ValueConverter enables EF to track the converted entity.
public static class ValueConversionExtensions
{
public static PropertyBuilder<T> HasJsonConversion<T>(this PropertyBuilder<T> propertyBuilder) where T : class, new()
{
ValueConverter<T, string> converter = new ValueConverter<T, string>
(
v => JsonConvert.SerializeObject(v),
v => JsonConvert.DeserializeObject<T>(v) ?? new T()
);
ValueComparer<T> comparer = new ValueComparer<T>
(
(l, r) => JsonConvert.SerializeObject(l) == JsonConvert.SerializeObject(r),
v => v == null ? 0 : JsonConvert.SerializeObject(v).GetHashCode(),
v => JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(v))
);
propertyBuilder.HasConversion(converter);
propertyBuilder.Metadata.SetValueConverter(converter);
propertyBuilder.Metadata.SetValueComparer(comparer);
return propertyBuilder;
}
}
Upvotes: 8