How to refactor parts of an EF select - entity-framework

Let's say I have the following EF code:
context.Employees.Select(e => e
{
FullName = e.FirstName + " " + e.LastName,
StartDate = e.StartDate,
... // Grab other data
};
Now maybe I notice that I construct the full name in multiple places, but would like in centralized. Is it possible to refactor this?
If I make it a method or a Func, I get EF errors, because it can't translate it into SQL.
NOTE: This is a simple example, assume it can get much more complicated with "Select"s, "Where"s, whatever in the assignment, so adding a ToList and then running additional code would be suboptimal and does not fit the definition of refactoring since I would have to change functionality and not just make it more maintainable.

One solution is to use the AsExpandable method from LinqKit:
Expression<Func<Employee,string>> fullName = e => e.FirstName + " " + e.LastName;
context.Employees.AsExpandable().Select(e => e
{
FullName = fullName.Compile().Invoke(e),
StartDate = e.StartDate,
... // Grab other data
};
From the linked article:
Compile is an inbuilt method in the Expression class. It converts the
Expression into a plain Func which
satisfies the compiler. Of course, if this method actually ran, we'd
end up with compiled IL code instead of an expression tree, and LINQ
to SQL or Entity Framework would throw an exception. But here's the
clever part: Compile never actually runs; nor does LINQ to SQL or
Entity Framework ever get to see it. The call to Compile gets stripped
out entirely by a special wrapper that was created by calling
AsExpandable, and substituted for a correct expression tree.
Alternatively, you could look into creating an Model Defined Function with Entity Framework. There's also the Microsoft.Linq.Translations library if you want to define a FullName property on the Employee class itself.

I think the better centralized way to do it in the entity class itself. You can add ReadOnly property to your entity class which should be NotMapped to the database to return required formatted data.
Public class Employee
{
//...
public string fullName{get { return FirstName + " " + LastName;}}
}

Related

EntityFramework and Expressions translation

I have a entity class Foo I've made partial containing the following code
private readonly static Expression<Func<Foo, int>> MyKeyExpression = (x) => x.Key;
public int MyKey
{
get { return MyKeyExpression.Compile()(this); }
}
The above works as in I can use MyKey in EntityFrameworks linq queries.
Why don't the following work?
private readonly static Expression<Func<Foo, int>> MyKeyExpression = (x) => x.Key;
// Set in the constructor with
// _myKeyDelegate = MyKeyExpression.Compile();
private readonly Func<Foo,int> _myKeyDelegate;
public int MyKey
{
get { return _myKeyDelegate(this); }
}
I understand the difference between a delegate and an expression(or maybe i don't?) but is confused how EntityFramework is able to interpret the property differently since MyKeyExpression.Compile() returns just that delegate which is then invoked returning an int. Perhaps its my lack of understanding of how the compiler actually handles C# Properties?
Example of usage where first example works but second examples throw a exception about not being able to translate it to SQL.:
dbContext.Foo.Delete(x => x.MyKey == 5)
I would say you don't fully understand difference between delegates and expressions.
Delegate is a reference to code compiled into IL. Only thing you can with it is execute it within .net CLR.
Expression object is a expression represented as tree, (you can think of AST). You can compile it to IL (Compile method) or you can inspect it and generate code for other execution environment, for example into SQL (that's what EF does).
When C# compiler compiles code, first it builds syntax tree and then compiles it. Basically expression is result of first part without second, so you could use SQL translator to compile it to SQL. Or you can write you own and translate it to anything else.
It's very strange what you are saying...
EF ignores the content of the getter and the setter of a mapped property (MyKey).
The query should be generated with a WHERE clause based on MyKey independent of what getter does.
How did you map the MyKey property? There is the setter missing so EF does not generate a field on the DB table and does not map it automatically.

Null Reference to Entity Association when overriding ToString in partial class - EntityDataSource.Include is being ignored

I am using Dynamic Data for Entity Framework, unfortunately I'm stuck on .NET 3.5, so it's EF1, and at the moment this cannot change.
So my problem is this, I have tried adding the EntityDataSource.Include property in a couple of ways to deal with the null reference I am getting when overriding the ToString method in a partial class for table1. I have tried setting the Include in markup on the EntityDataSource declaration and also by setting EntityDataSource.Include = "table2.table3" in the EntityDataSource.Selecting event, both no luck.
As you can see, I need to add an include to an association of an association. I want to display "table3.name + table2.Date" in the override ToString method for table2, and reflected in the dropdownlist for the association reference when in edit mode on table1.
Mind you, the Include works just fine on the GridDataSource, for whatever reason I am having issues on the DetailsDataSource.
I have found a work-around, that being to check if the association reference is loaded in the ToString override, and if not load it.
public override string ToString()
{
if (this.Course == null)
{
if (!this.CourseReference.IsLoaded)
this.CourseReference.Load();
return this.Course.Name + " - " + string.Format("{0:yyyy-MM-dd}", this.StartDate.Date);
}
else
return this.Course.Name + " - " + string.Format("{0:yyyy-MM-dd}", this.StartDate.Date);
}

Can LINQ-To-Entities be expanded?

In general, If I create an extension method that acts on an entity:
public static MyEntity Foo(this MyEntity entity)
{
// do something to the entity
}
One cannot directly use this in a projection from Linq-To-Entities such as follows:
var result = myContext.MyEntities.Select(x=> x.Foo());
Doing so yields an error such as:
System.NotSupportedException: LINQ to Entities does not recognize the
method 'Foo(MyEntity)' method, and this method cannot be translated
into a store expression.
I fully understand why this error occurs. My question is this: If I can provide an implementation of Foo that uses an expression tree, is there some way that I can add Foo to the operations that LINQ-to-entities understands? And if so - how?
Note: I can certainly convert it to a list like this:
var result = myContext.MyEntities.ToList().Select(x=> x.Foo());
And it doesn't error. But I no longer have an IQueryable. I have an IEnumerable. If I were to use it like this:
var result = myContext.MyEntities.ToList().Select(x=> x.Foo()).First();
I would end up fetching ALL entities before taking the top one and discarding the rest - which would be horrible for performance.
Use LINQKit project, but instead of your method foo, You will be obliged to write expression tree which is equivalent.

EF1: Filtering derived types of entity class using .OfType<> by passing a string value

I have a situation where I'm trying to filter a LINQ select using a derived sub class.
ctx.BaseEntity.OfType<SubClass>() - this works fine.
However I'd like to do this using a string value instead. I've come across a performance barrier when I have lots (>20) Sub Classes and selecting an Entity without using OfType just isn't an option. I have a generic UI that renders from the base class, so I don't know what Class Type will be returned at compile time.
So what I'd like to do is this:
Perform a projected Select where I
return just the SubClassType from
the database
Perform a second select
using this value as the OfType to
only select the relevant related
entity from the database (No mass
unions generated)
int id = 1;
var classType = (from c in ctx.BaseClass.Include("ClassType")
where c.id == id
select new
{
c.ClassType.TypeName
}).First();
BaseClass caseQuery = ctx.BaseClass.OfType<classType.TypeName>()
.Include("ClassType")
.Include("ChildEntity1")
.Include("ChildEntity2")
.Where(x => x.id== id);
But obviously this won't work because OfType requires a Type and not a string.
Any ideas on how I can achieve this?
Update:
As a side note to the original question, it turns out that the moment you project a query that uses a Navigation Property - it builds the monster SQL too, so I've ended up using a stored procedure to populate my ClassType entity from the BaseClass Id.
So I've just got it to work using eSQL, which I'd never used before. I've posted the code here just in case it helps someone. Has anyone else got a more strongly typed solution they can think of?
BaseClass caseQuery = ctx.BaseClass.CreateQuery<BaseClass>("SELECT VALUE c FROM OFTYPE(Entities.[BaseClass],namespace.[" + classType.TypeName + "]) as c")
.Include("ClassType")
.Include("ChildEntity1")
.Include("ChildEntity2")
.Where(x => x.id== id).FirstOrDefault();
To answer the headline question about calling OfType with a string / runtime type, you can do the following:
// Get the type, assuming the derived type is defined in the same assembly
// as the base class and you have the type name as a string
var typeToFilter = typeof(BaseClass)
.Assembly
.GetType("Namespace." + derivedTypeName);
// The use reflection to get the OfType method and call it directly
MethodInfo ofType = typeof(Queryable).GetMethod("OfType");
MethodInfo ofTypeGeneric = method.MakeGenericMethod(new Type[] { typeToFilter });
var result = (IQueryable<Equipment>)generic.Invoke(null, new object[] { equipment });
Combine this with your stored procedure to get the class name and you (should?) avoid the massive join - I don't have table-per-type implementation to play with so I can't test.

How call a custom method in lambda expression . I Use Entity Framework 4 . Stored expression error

Is it possible to call a custom method in a lambda expression.?
//Address a : It's an Entity
public string AddressConstructor(Address a)
{
return a.City + "," + a.Province;
}
var Test = _db.MyTableTest.Select( t => new ViewModel
{
MyID = t.ID,
StringAddress = AddressConstructor(t.Addr)
};
You should be able to accomplish this using LINQKit to inline your expression into the expression tree.
http://www.albahari.com/nutshell/linqkit.aspx
This will cause the concatanation you're attempting to be run on the SQL Server, not in memory (as described in the other answer). SQL Server of course knows how to concatanate strings, but if your AddressConstructor did something else that SQL Server doesn't understand, then this approach would not work and you would indeed need to perform your custom method in memory using the approach described in the other answer.
Essentially LINQKit will flatten the tree so it actually gets executed as:
var Test = _db.MyTableTest.Select( t => new ViewModel
{
MyID = t.ID,
StringAddress = t.Addr.City + "," + t.Addr.Province
};
which EF should have no problem executing (and the concatenation should happen on the SQL Server).
You need to call AsEnumerable so that the projection is executed locally:
var Test = _db.MyTableTest.AsEnumerable()
.Select( t => new ViewModel
{
MyID = t.ID,
StringAddress = AddressConstructor(t.Addr)
};
Otherwise, the Queryable.Select method is used instead of Enumerable.Select, which causes Entity Framework to try to translate the lambda expression to a SQL query (which of course is not possible in that case)