// настройка полей с помощью Fluent API modelBuilder.Entity<Customer>() .Property(c => c.FirstName).IsRequired().HasMaxLength(30); modelBuilder.Entity<Customer>() .Property(c => c.Email).HasMaxLength(100); modelBuilder.Entity<Customer>() .Property(c => c.Photo).HasColumnType("image"); 

What are these instructions in the code above?

 c => c.FirstName c => c.Email c => c.Photo 

2 answers 2

Constructions of the form x => x.Email (as well as more complex ones, of the form (x, y) => x.Email + y.Age or there n => { int s = 0; while (n-- > 0) s += n * n; return s; } ) are lambda expressions . They are used in C # in two ways.

If at this point a delegate / method / something is expected , then a lambda has the meaning of a locally defined function. For example, the following code:

 Func<Entity, string> f = (c => c.FirstName); 

essentially no different from code

 Func<Entity, string> f = GetFirstName; 
 static string GetFirstName(Entity c) { return c.FirstName; } 

(but recorded faster). In addition (and this is very important and convenient), lambdas can refer to local variables and fields visible at the definition point. For example:

 int x = hey.GimmeSomeX(); Func<int, int> f = n => n * x; 

This effect can no longer be achieved with a local function, so the compiler “under the hood” uses a more complex structure.


If in the place where the lambda is mentioned, a special thing is expected called the expression tree , then the lambda is converted into this expression tree. Having a tree of expressions, you can see programmatically what is inside. In particular, if you have c.FirstName , you can see that this is a call to a field named FirstName . That's what it is used for in your example.

How is the expression tree better than just passing the string "FirstName" ? The fact is that in the string you may be mistaken, but the compiler follows the correctness of the lambda expression. Also, when you rename the IDE will be able to correctly pick up the changes. And with the string are possible, of course, problems.

    Such code is used in C # to specify the name of the property without the risk of being sealed. In classic code, this might look like this:

     modelBuilder.Entity<Customer>() .Property("FirstName") .IsRequired() .HasMaxLength(30); 

    It is clear that when you rename the FirstName property, the code continues to compile, but stops working at run time. It would be nice to use such a construction that, when renaming a property, would lead to a compilation error. This would enable us to immediately detect and correct typos in the field names.

    Just for this and apply the syntax based on expression trees:

     public PrimitivePropertyConfiguration Property<T>( Expression<Func<TStructuralType, T>> propertyExpression ) where T : struct, new() { . . . } 

    The syntax is scary, but it allows you to statically typify the call to any class property. What happens in this case?

    Func<TStructuralType, T> means that a lambda expression is expected at the input, it is an anonymous ( nameless ) function. The syntax of such functions in C # looks like x => Exp(x) , where x is a function parameter, and Exp(x) is some kind of not very complicated expression. In our case, this simple expression is an appeal to the property of the object.

    Expression<Func<TStructuralType, T>> means that we will not perform the function directly, but instead build the expression tree and store it in a variable of type Expression .

    An object of this class will be available at runtime and we will be able to walk through it and retrieve the name of the property.

    The fact that this Expression is from Func<TStructuralType, T> limits the way of setting the propertyExpression parameter: we are waiting for either the function name with one parameter or the anonymous function with one parameter (also known as lambda).

    Simply put, Expression<Func<TStructuralType, T>> means that when you call Property , something like x => Exp(x) is expected as a parameter. You can still shoot yourself in the foot and write an inappropriate expression, for example, x => x + x , but you shouldn’t do it anyway.

    Finally, what is the main magic, how is the Property method arranged? The basis, of course, is reflection and details can be found in the answer to the corresponding question on StackOverflow (English) .

    Directly in the Entity Framework, methods that retrieve the name of a property from an expression are moved to the ExpressionExtensions class.