5

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?
2
  • Sure it does, you can check by disabling proxy creation (to be sure), then fetch some entity, then do ctx.Entry(someEntity).Property("WhateverProperty").CurrentValue = 1; and observe that value of someEntity.WhateverProperty has changed, which could not be done without some form of reflection. Though of course all reflection is cached (in form of compiled delegates), so it's not actually that slow - there is nothing like GetProperty("WhateverProperty").SetValue(entity, 1) every time you do this. Commented Mar 10, 2018 at 15:59
  • 2
    @CodingYoshi My answer is wrong. Because in both cases that cashed delegate is called. Commented Mar 10, 2018 at 16:54

3 Answers 3

5

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;
Sign up to request clarification or add additional context in comments.

4 Comments

What is your opinion about @AramKocharyan answer because your answer contradicts that answer?
Well, I'm pretty sure my answer is correct. Why - because when I put breakpoint on my entity property setter, the calling stack shows that the property setter is called from the aforementioned method :)
But that answer has code to backup the remarks. I want to be sure about who may be correct.
I mean, there are different paths and intermediate calls, but they all at the end hit this method (with or w/o proxy). And the setter delegate is cached in the EdmProperty.ValueSetter internal member.
2

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.

2 Comments

In fact the actual implementation maps to SetViaCompiledExpressionTrees, so it's not the fastest possible method, but still order of magnitude faster than reflection.
Ah yes, you're right, because of Action<object,object>, otherwise it would've been a strong typed Func. Tnx.
-1

@CodingYoshi thanks you help me a lot previously, I know may I am not qualified to answer one of your questions, but I am really digging a lot about this discussion, and I found answer I think it's true and logically after I read this chapter from MSDN.

It mentions that you can access a property as a string or as an expression like this:

string currentName1 = context.Entry(blog).Property(u => u.Name).CurrentValue; 

Without mentioning reflection or the System.Reflection namespace and the implementation not even on top of the System.Reflection namespace and the tutorial not even mention any cost within access property within entity by this way, so in my humble experience with Microsoft I think this snippet do not have the cost of reflection.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.