Today I discovered a weird behavior in
Entity Framerwork. When I set the value of an entity to the same value as in the database, it would still say the value had been changed. This is the case of all values except the primary key value.
This means that we would unnecessary update the value on
SaveChanges(). How could we change this behavior? I went to Google for an answer and found one on
StackOverflow, but unfortunately it can't find it again.
But basically the fix is to edit the
T4 template used to generate to entities. The easiest way to do this is to change the Code Generation item by right clicking on the EF design surface, click "Add Code Generation Item..." and choose "
ADO.NET EntityObject Generator". This adds a T4 template to the project, which we can edit to check if the value are the same as the original.
Somewhere in the template in my case at line 552, in the .tt file, the following part needs to be changed.
/// <summary>
/// <#=SummaryComment(primitiveProperty)#>
/// </summary><#=LongDescriptionCommentElement(primitiveProperty, 1)#>
[EdmScalarPropertyAttribute(EntityKeyProperty=<#=code.CreateLiteral(ef.IsKey(primitiveProperty))#>, IsNullable=<#=code.CreateLiteral(ef.IsNullable(primitiveProperty))#>)]
[DataMemberAttribute()]
<#=code.SpaceAfter(NewModifier(primitiveProperty))#><#=Accessibility.ForProperty(primitiveProperty)#> <#=code.Escape(primitiveProperty.TypeUsage)#> <#=code.Escape(primitiveProperty)#>
{
<#=code.SpaceAfter(Accessibility.ForGetter(primitiveProperty))#>get
{
if (ef.ClrType(primitiveProperty.TypeUsage) == typeof(byte[]))
{
return StructuralObject.GetValidValue(<#=code.FieldName(primitiveProperty)#>);
}
else
{
#>
return <#=code.FieldName(primitiveProperty)#>;
<#+
}
#>
}
<#=code.SpaceAfter(Accessibility.ForSetter((primitiveProperty)))#>set
{
<#+
if (ef.IsKey(primitiveProperty))
{
if (ef.ClrType(primitiveProperty.TypeUsage) == typeof(byte[]))
{
#>
if (!StructuralObject.BinaryEquals(<#=code.FieldName(primitiveProperty)#>, value))
<#+
}
else
{
#>
if (<#=code.FieldName(primitiveProperty)#> != value)
<#+
}
#>
{
<#+
PushIndent(CodeRegion.GetIndent(1));
}
#>
<#=ChangingMethodName(primitiveProperty)#>(value);
ReportPropertyChanging("<#=primitiveProperty.Name#>");
<#=code.FieldName(primitiveProperty)#> = StructuralObject.SetValidValue(value<#=OptionalNullableParameterForSetValidValue(primitiveProperty, code)#>);
ReportPropertyChanged("<#=primitiveProperty.Name#>");
<#=ChangedMethodName(primitiveProperty)#>();
<#+
if (ef.IsKey(primitiveProperty))
{
PopIndent();
#>
}
<#+
}
#>
}
}
The fix lies in removing the
if (ef.IsKey(primitiveProperty))
statement to always check if the value are different. The solution is to replaces to code block above with this code block:
/// <summary>
/// <#=SummaryComment(primitiveProperty)#>
/// </summary><#=LongDescriptionCommentElement(primitiveProperty, 1)#>
[EdmScalarPropertyAttribute(EntityKeyProperty=<#=code.CreateLiteral(ef.IsKey(primitiveProperty))#>, IsNullable=<#=code.CreateLiteral(ef.IsNullable(primitiveProperty))#>)]
[DataMemberAttribute()]
<#=code.SpaceAfter(NewModifier(primitiveProperty))#><#=Accessibility.ForProperty(primitiveProperty)#> <#=code.Escape(primitiveProperty.TypeUsage)#> <#=code.Escape(primitiveProperty)#>
{
<#=code.SpaceAfter(Accessibility.ForGetter(primitiveProperty))#>get
{
<#+ if (ef.ClrType(primitiveProperty.TypeUsage) == typeof(byte[]))
{
#>
return StructuralObject.GetValidValue(<#=code.FieldName(primitiveProperty)#>);
<#+
}
else
{
#>
return <#=code.FieldName(primitiveProperty)#>;
<#+
}
#>
}
<#=code.SpaceAfter(Accessibility.ForSetter((primitiveProperty)))#>set
{
<#+
if (ef.ClrType(primitiveProperty.TypeUsage) == typeof(byte[]))
{
#>
if (!StructuralObject.BinaryEquals(<#=code.FieldName(primitiveProperty)#>, value))
<#+
}
else
{
#>
if (<#=code.FieldName(primitiveProperty)#> != value)
{
<#+
PushIndent(CodeRegion.GetIndent(1));
}
#>
<#=ChangingMethodName(primitiveProperty)#>(value);
ReportPropertyChanging("<#=primitiveProperty.Name#>");
<#=code.FieldName(primitiveProperty)#> = StructuralObject.SetValidValue(value<#=OptionalNullableParameterForSetValidValue(primitiveProperty, code)#>);
ReportPropertyChanged("<#=primitiveProperty.Name#>");
<#=ChangedMethodName(primitiveProperty)#>();
<#+
PopIndent();
#>
}
}
}