Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does the Entity Framework DbEntityEntry.Property method use reflection?

This question is about this code:

entityEntry.Property("WhateverProperty").CurrentValue = 1;

I answered this question yesterday and if you notice in the comments to the question (not the answer), one of the members @gertarnold said this:

entityEntry.Property("InsertedBy") doesn't use reflection, it reads the EF metadata.

Sure it uses the EF metadata to figure out if the entity has that property but I am pretty sure somewhere down the line they would have to use reflection to set the property.

I tried looking at the source code here, here and here (line 484) and then chickened out.

So the questions are:

  1. Does it use reflection?
  2. If not, how is the property set then?
like image 409
CodingYoshi Avatar asked Mar 10 '18 15:03

CodingYoshi


2 Answers

It does not use reflection (the reflection is done at the time metadata model is created), but one time built and cached delegate from compiled dynamic expression.

The code that does the actual property set is here:

internal static void SetValue(EdmProperty property, object target, object value)
{
    var setter = GetSetterDelegateForProperty(property);    
    setter(target, value);    
}

and building the expression and compiling the delegate is here.

Basically it creates, caches and uses something like this:

Action<object, object> setter = (target, value) =>
    ((TEntity)target).Property = (TValue)value;
like image 120
Ivan Stoev Avatar answered Oct 27 '22 02:10

Ivan Stoev


EntitEntry.CurrentValue ends up setting a property value in EdmProperty by calling a compiled expression tree built once (when building the entity model, and then using reflection) and cached as Action:

// <summary>
// cached dynamic method to set a CLR property value on a CLR instance
// </summary>
internal Action<object, object> ValueSetter
{
    get { return _memberSetter; }
    set
    {
        DebugCheck.NotNull(value);
        // It doesn't matter which delegate wins, but only one should be jitted
        Interlocked.CompareExchange(ref _memberSetter, value, null);
    }
}

Setting a property by this method is roughly 8 times slower than directly setting it, but still a great deal faster than reflection, even when the PropertyInfo is cached. This is demonstrated here. To summarize:

Writing a Property (‘Set’)              

Method                         Mean
=========================================== 
SetViaProperty                    1.4043 ns         
SetViaDelegate                    2.8215 ns
SetViaILEmit                      2.8226 ns         
SetViaCompiledExpressionTrees    10.7329 ns <=      
SetViaFastMember                 36.6210 ns         
SetViaReflectionWithCaching     214.4321 ns         
SetViaReflection                287.1039 ns         
SetViaDelegateDynamicInvoke     922.4618 ns         

So, as expected, EF uses the fastest possible method to set a property value in an object of which it has to determine the setter at runtime. The faster methods require compile-time knowledge of entity types or a third-party library.

like image 32
Gert Arnold Avatar answered Oct 27 '22 01:10

Gert Arnold