I'm trying to do some eager loading on an EF Entity.
so, if the entity is called Orders .. then I guess i would do the following...
_someContext.Orders.Include("Whatever") ....
But the problem is, I have a method like the following ...
public IQueryable<Order> Find(Expression<Func<Order, bool>> predicate)
{
return CurrentContext.Orders.Where(predicate);
}
which works great .. but can i leverage the Expression predicate to include the Include("whatever") in there, instead of having to add another method parameter?
I don't think so. Since the predicate and ObjectQuery.Where Method in genral has nothing to do with eager loading by Include. You can create a extension method though, but that does not save you from having yet another parameter for specifying the include:
public IQueryable<Order> Find(Expression<Func> predicate, string include) {
return CurrentContext.Orders.Where(predicate, include);
}
public static ObjectQuery<T> Where<T>(this ObjectQuery<T> entity, Expression<Func<T, bool>> predicate, string include) {
return (ObjectQuery<T>)entity.Include(include).Where<T>(predicate);
}
Related
My Code:
internal DbSet<TEntity> DbSet;
public virtual IEnumerable<TEntity> Get()
{
IQueryable<TEntity> query = DbSet;
return query.ToList();
}
As you can see above we are calling ToList() method. When I go into IQueryable, I have seen that it gets inheritence from IEnumerable but in IEnumerable I can not see any ToList() method. Where and how this method comes from? Can you help me please.
The extension methods provided for IQueryable<T> and IEnumerable<T> are generally respectively found in the types Queryable and Enumerable.
Keep in mind that the former are interfaces. Interfaces can't have implementations defined. These are extension methods (with implementation) which means they need to be defined in a static class as static methods.
Queryable [MSDN]
Enumerable [MSDN]
Extension Methods [MSDN]
While somewhat powerful, the System.Linq.Dynamic library has a surprising lack of documentation, especially in regards to what conventions must be followed for more complex queries.
In a query I'm working on, it contains a FirstOrDefault call, but I can't seem to get it to work.
Here's the whole (unworking) expression:
"Locations.FirstOrDefault(x => x.IsPrimaryLocation).Address1 as Address"
Can I write this FirstOrDefault expression to work with Dynamic linq?
What is the correct way to write this expression?
Extending the dynamic library is certainly an option as already suggested.
an alternative given the Where in Dynamic Linq returns an Iqueryable
public static class DynamicQueryable {
public static IQueryable<T> Where<T>(this IQueryable<T> source, string predicate, params object[] values) { return (IQueryable<T>) Where((IQueryable) source, predicate, values); }
public static IQueryable Where(this IQueryable source, string predicate, params object[] values) {
using a DYnamic Object for the context or repository "locations".
Then use a where which could contain dynamic string predicate and follow with firstOrDefault.
(catch or test for null not considered)
DynamicLocations.Where(x => x.IsPrimaryLocation).FirstOrDefault( ).Address1 as Address;
or dynamic where if needed
DynamicLocations.Where("IsPrimaryLocation",new string[]).FirstOrDefault( ).Address1 as Address;
Details:
You can expose on a method on a generic repository Class which you instantiate as a dynamic
public virtual IQueryable<TPoco> DynamicWhere(string predicate, params object[] values) {
return AllQ().Where(predicate, values);
}
Dynamic Generic Repository instantiation Sample
public class RepositoryFactory<TPoco> where TPoco : BaseObject,new() {
public IRepositoryBase<TPoco> GetRepository(DbContext context) {
// get the Pocotype for generic repository instantiation
var pocoTypes = new[] {typeof (TPoco)}; // but supports <T,U>
Type repBaseType = typeof (RepositoryBase<>);
IRepositoryBase<TPoco> repository = InstantiateRepository(context, repBaseType, pocoTypes);
return repository;
}
private IRepositoryBase<TPoco> InstantiateRepository(DbContext context, Type repType, params Type[] args) {
Type repGenericType = repType.MakeGenericType(args);
object repInstance = Activator.CreateInstance(repGenericType, context);
return (IRepositoryBase<TPoco>)repInstance;
}
}
I am trying to apply additional server-side filtering to entities exposed by an asp.net OData service, using Linq to Entities.
So far so good, but the Linq query that I build for the filter can sometimes get to an enormous length, causing a StackOverflowException.
As a workaround, I want to execute the query in a separate thread, giving that thread a bigger stack size limit. To achieve this, I implemented an IQueryable and IQueryProvider wrappers, so that when the IQueryable's Execute method is called, it would be executed in a separate thread.
To keep it simple and focused on my problem, I will omit the threading part in the following code samples, as this is not the issue here.
Here's the relevant parts of the code:
public class MyQueryable<T> : IQueryable<T> {
private IQueryable<T> _Inner { get; set; }
private IQueryProvider _Provider { get; set; }
public MyQueryable(IQueryable<T> inner) {
_Inner = inner;
_Provider = new MyQueryProvider(inner.Provider);
}
public Type ElementType {
get { return _Inner.ElementType; }
}
public Expression Expression {
get { return _Inner.Expression; }
}
public IQueryProvider {
get { return _Provider; }
}
/* ... Implementations of GetEnumerator ... */
}
public class MyQueryProvider : IQueryProvider {
private IQueryProvider _Inner { get; set; }
public MyQueryProvider(IQueryProvider inner) {
_Inner = inner;
}
public IQueryable<T> CreateQuery<T>(Expression expression) {
return new MyQueryable<T>(_Inner.CreateQuery<T>(expression));
}
public T Execute<T>(Expression expression) {
// The problem occurs on the following line.
return _Inner.Execute<T>(expression);
}
/* ... Implementation of the non-generic versions of CreateQuery, Execute ... */
}
When I run this, I get an InvalidOperationException in MyQueryProvider.Execute method:
Cannot compare elements of type 'System.Collections.Generic.ICollection`1'.
Only primitive types (such as Int32, String, and Guid) and entity types are supported.
This is how I build the original IQueryable that is being passed to MyQueryable:
I get the DbSet from my entities context, apply OData filter query option on it, and call Count(). Something along the lines of:
((odataQueryOptions.Filter.ApplyTo(
context.Entities.AsQueryable(), new ODataQuerySettings()))
as IQueryable<Entity>).Count()
I partially identified that the problem is that the odata filter query option contains a nested 'any' filter, something like:
Entities/$filter=RelatedEntities/any(entity: (entity/ID eq 1))
which adds a check to the IQueryable's Where expression whether the RelatedEntities collection is null. This check is suppostedly what causes the above exception.
What I cannot understand, is why the original IQueryable fails when I try to delegate the Execute method's execution to it from the MyQueryable.Execute method, but it all works fine when I use the original IQueryable directly.
Any help on this would be highly appreciated. Thanks in advance.
I'm implementing the service \ repository pattern in a new project. I've got a base interface that looks like this. Everything works great until I need to use the GetMany method. I'm just not sure how to pass a LINQ expression into the GetMany method. For example how would I simply sort a list of objects of type name?
nameRepository.GetMany( ? )
public interface IRepository<T> where T : class
{
void Add(T entity);
void Update(T entity);
void Delete(T entity);
void Delete(Expression<Func<T, bool>> where);
T GetById(long Id);
T GetById(string Id);
T Get(Expression<Func<T, bool>> where);
IEnumerable<T> GetAll();
IEnumerable<T> GetMany(Expression<Func<T, bool>> where);
}
public virtual IEnumerable<T> GetMany(Expression<Func<T, bool>> where)
{
return dbset.Where(where).ToList();
}
Assuming that you had an implementation of IRepository<MyClass>, you would make a call to GetMany like so:
IRepository<MyClass> repository = ...;
IEnumerable<MyClass> filtered = repository.GetMany(
mc => true);
Note the mc => true lambda expression. mc in this case is the parameter (in this case, of type MyClass) passed to the Expression<Func<T, bool>> which will be evaluated (one would assume through an IQueryable<T>) and the mc.SomeProperty == someValue is an expression which returns true, which is the second type parameter of the Expression<Func<T, bool>>.
Once you have the filtered, you can use the order by clause (or the OrderBy extension method, they're the same) to sort the results, like so:
var filteredAndOrdered = filtered.OrderBy(mc => mc.MyProperty);
Note that GetMany returns an IEnumerable<T>, not an IQueryable<T>; this is important if your result set is large, as the ordering will happen on the client, and not be sent to the server.
For an OrderBy operation, this can be expensive because it has to go through the entire sequence (to order) before returning the first result.
I've been looking around the web but I've yet to found any information on this. As we know Linq gives us CompiledQuery which transform the expression into T-SQL before running it. I'm trying to design a generic repository to interact with my EF but with the exception the Linq queries is compiled. If anyone could shead some light on this that would be great :)
It is hardly possible because if you want to pre-compile query you must know it. With generic repository you usually have only this:
public interface IRepository<T>
{
IQueryable<T> GetQuery();
}
So the code using a repository instance is responsible for defining the query. Pre-compilation requires concrete repository which will contain methods like:
IEnumerable<Order> GetOrdersWithHeaderAndItemsByDate(DateTime date, int take, int skip);
IEnumerable<OrderHeader> GetOrderHeadersOrderedByCustomer(int take, int skip);
etc.
Obviously you can hardly prepare such queries in generic repository beacuse they are dependent on concrete entity.
You are looking for an implementation of the Specification pattern. Basically, this is creating a Specification object that contains the information needed to filter your query. By using Specifications, you can have a Generic Repository implementation, and put your custom query logic in the specification. The specification base class looks something like:
public class Specification<TEntity>
{
public Specification(Expression<Func<TEntity, bool>> predicate)
{
_predicate = predicate;
}
public bool IsSatisfiedBy(TEntity entity)
{
return _predicate.Compile().Invoke(entity);
}
public Expression<Func<TEntity,bool>> PredicateExpression{
get{ return _predicate; }
}
private Expression<Func<TEntity, bool>> _predicate;
}
A very helpful article about implementing the specification pattern with the Entity Framework can be found at http://huyrua.wordpress.com/2010/07/13/entity-framework-4-poco-repository-and-specification-pattern/