What prevents Entity Framework from creating classes when projecting using Select? - entity-framework

Usually when I query with Entity Framework I do something like the following:
using (var db = MyDataContext()){
db.MyTable.Select(d => new DataModel(){
Id = d.Id,
Name = d.Name
});
}
But sometimes I get an error at runtime "the entity or complex type 'DataModel' cannot be constructed in a linq to entities query". How can I know if a type can be constructed without running the program and testing?

Related

Asp.Net Core Automapper LINQ expression

I'm currently working with ASP.NET Core and I want to use Automapper to map a Linq Expression. The mapping statement is:
var targetConditions = _mapper.Map<Expression<Func<Entity, bool>>>(filter);
where filter is a formal parameter in the form:
(Expression<Func<EntityDTO, bool>> filter
In the mapping profile I have the following map created:
CreateMap<Expression<Func<EntityDTO, bool>>, Expression<Func<Entity, bool>>>();
I'm using a generic repository pattern with EF. I want to get a list of DTOs filtered by, of course, DTO's fields from my controller. I then need to convert from DTO filter to entities filter in the Business Layer before doing any query using Linq for EF.
Even though the expression does get coverted from EntityDTO to Entity, the parameters in the lambda expressions inside don't, raising all sorts of errors when I further use it with EF. Any idea how can this be done?
Try this:
IQueryable<Customer> query = repository.getCustomers(); // entities query
query.ProjectTo<CustomerDto>().Where(dtoFilterExpression)

EF eager load collection in projection with GroupJoin

I am trying to make a left join with Linq to Entities in EF and eager load a collection in one of the entities.
The left join works with this code:
var joinedResult = context.Set<Client>()
.GroupJoin(
context.Set<Project>(),
client => client.Id,
project => project.ClientId,
(client, projects) => new
{
Client = client,
Project = projects.FirstOrDefault()
})
.ToList();
Now the Client entity has a Categories collection I want to load. Since this is a projection, I cannot include the collection before performing the group join, neither after the join since I am creating an anonymous type.
I tried to add the collection in the anonymous type as suggested by this anwser to a similar question:
ClientCategories = client.Categories.Select(s => s.Name),
but i keep getting an ObjectDisposedException when accessing the collection from the Client object outside the business layer.
Accessing the field directly after the query before returning from the business layer like this:
joinedResult.ForEach(result => result.Client.Categories.Count() /* NOP */);
works, but of course it results in a new database query per result.
How should I proceed to load this collection ?

Dynamic EF Query

I am thinking of designing a business rule engine which basically generates an EF query from a set of string values stored in a database.
For e.g. I will store the connection string, table name, the where condition predicate, and select predicate as string fields in a db and would like to construct the EF query dynamically. For e.g.
var db = new DbContext(“connectionstring”);
var wherePredicate = Expression.FromString(“p => p.StartDate > new DateTime(2014,5,1))
var selectPredicate = Expression.FromString(“p => p”)
var results = db.Set(“Projects”).Where(wherepredicate).Select(selectPredicate)
For constructing the predicates I can use DynamicExpression or Dynamic LINQ library.
However how do I access db.Set(“Projects”) where Projects is the entity name and apply the where and select predicates? (or something like db[“Projects”].Where().Select).
I tried the non-generic version of the DbContext.Set(Type entityttype) method, however couldn’t figure out how to apply Where and Select predicates to the returned object.
I am trying to avoid generating SQL queries and instead rely on dynamically generated EF code.
This doesn't make much sense. You can create method that will work on string instead of generic type using reflection, but you'd have to return DbSet not DBSet<T>. And on that one you cannot execute LINQ's methods (basically), because there's no type (during compilation). Of course you can do it all the way using reflection, but then, why??? You're loosing 90% of what O/R mapper does for you.

The LINQ expression node type 'ArrayIndex' is not supported in LINQ to Entities. but is supported by linq-to-sql

A project just switched from linq-to-sql to linq-to-entities, and now I get the error
The LINQ expression node type 'ArrayIndex' is not supported in LINQ to Entities.
for this line:
var a = db.Table.Single(d => d.Date == dates[0]);
(Fixing it in this particular case is easy, as in
var firstDate = dates[0];
var a = db.Table.Single(d => d.Date == firstDate);
)
But why does this work in linq-to-sql but not in linq-to-entities?
Did they make linq-to-entities worse than linq-to-sql?
What am I missing?
That's because L2E just tries to translate your query to a sql command. So, any additional things (methods like .ToString(), and other things which can't be translated to SQL) leads to that exception.
However, L2S like linq to objects implements IEnumerable. So, the goal of them is different: L2E to translate linq queries to sql commands, L2O to work with in-memory IEnumerable objects, and L2S to model and work with a database.
Now, if want to be able to use your L2S queries in your EF project(using L2E), you should first convert your data retrieved from you DbContext to IEnumerable:
var a = db.Table.AsEnumerable().Single(d => d.Date == dates[0]);
// or any other methods...

Restricting lazy loading while automapping EF entity type

Folks,
I am mapping EF objects to simple Pocos using automapper in my service layer. I have certain entities that have many relationships in EF,but I want to restrict how much of this gets pulled back from the db. One of these entities would map to a database table but would have many relationships to other tables that would appear as entity collections in the generated model (EDMX).
So I have created a "shallow" poco for the entity which only has poco properties for the first level of properties in the entity, i.e. some integer Ids instead of associated collections/entity collections. I map in the following manner....
var simplepocoforentity= Mapper.Map(_readOnlyDb.Single<EfEntity>(x => x.Id== Id),
new SimplPocoForEntity());
My question is.. because I am only mapping the entity to a simple poco here, can I be confident that EF will not try and query other non referenced data from the underlying db tables relationships when I do the mapping?
I know that I can investigate this via SQL Profiling, but I would appreciate any input befor going down that route.
Thanks
K.
It depends on the internal implementation of AutoMapper. I would assume that AutoMapper does not try to access the navigation properties of the entity (in which case lazy loading and an additional database query would kick in). I don't see a reason why AutoMapper should do this if you only map scalar properties. But who knows...
If you want to be on the safe side you could disable lazy loading temporarily:
try
{
_readOnlyDb.ContextOptions.LazyLoadingEnabled = false;
var simplepocoforentity = Mapper.Map(_readOnlyDb.Entities
.Single(x => x.Id == Id), new SimplPocoForEntity());
// ...
}
finally
{
_readOnlyDb.ContextOptions.LazyLoadingEnabled = true;
}
As a side note: Be aware that you load the full entity into the context with this approach. After that the mapping happens. Potentially you load more columns from the database than you really need (perhaps not in your special case here). In general I would do the mapping with a projection which ensures that the database only queries the columns which are needed:
var simplepocoforentity = _readOnlyDb.Entities
.Where(e => e.Id == Id)
.Select(e => new SimplPocoForEntity
{
PocoProperty1 = e.EntityProperty1,
PocoProperty2 = e.EntityProperty2,
PocoProperty3 = e.EntityProperty3
// etc.
})
.Single();
With this approach no lazy loading would happen at all because you don't load the entity but directly the PocoForEntity from the database.