I am using generic repository pattern with methods:
private ObjectQuery<T> ObjectQueryList()
{
var list = CamelTrapEntities.CreateQuery<T>(EntitySetName);
return list;
}
public IQueryable<T> List()
{
return ObjectQueryList();
}
Metod List() returns IQueryable<T>, becase IQueryable<T> is easy to mock. I also have extension method:
public static IQueryable<T> Include<T>(this IQueryable<T> obj, string path)
{
if (obj is ObjectQuery<T>)
(obj as ObjectQuery<T>).Include(path);
return obj;
}
This method is used outside of repository to get entity list with navigation properties already loaded, for example: List.Include("CreatedBy"). The problem is that it doesn't work. All includes are ignored. when I change List() method to
public ObjectQuery<T> List()
{
return ObjectQueryList();
}
everything works fine.
How should I implement repository pattern to be able to execute more complex queries?
Reflector gave me an answer:
public ObjectQuery<T> Include(string path)
{
EntityUtil.CheckStringArgument(path, "path");
return new ObjectQuery<T>(base.QueryState.Include<T>((ObjectQuery<T>) this, path));
}
Include returns new ObjectQuery object and my Include function returned old object. Changing to
public static IQueryable<T> Include<T>(this IQueryable<T> obj, string path)
{
if (obj is ObjectQuery<T>)
return (obj as ObjectQuery<T>).Include(path);
return obj;
}
solved the problem. Few hours lost and I hate Entity Framework more:)
It made me also realise that I should create another List function with Include parameter and not allow doing includes outside repository.
Here is the most comprehensive Repository pattern implementation I've seen for EF. I can't say for sure if it will allow you to do Include(), but if I read the implementation right it should.
With EntityFramework 4.1, DbExtensions (System.Data.Entity.DbExtensions) resolves this problem, and natively adds both .Include([string path]) and .Include([property expression]) for any IQueryable<T>.
Just be sure that the project using your repository references EntityFramework, and, as with any extension methods, specify using System.Data.Entity; in your class file to gain access to these extensions.
Related
I have a question about caching with Entity Framework code first.
I need to cache my query's results and I came about something that I didn't know.
Func<T, bool> predicate does not work when filtering whilst Expression<Func<T, bool>> predicate does.
Maybe I'm missing the obvious.
Here is my scenario:
Whenever I call a method, e.g."GetOrders", I use a method called "GetCachedModels" internally to get the cached version.
When subsequently many calls are made with
"GetOrders(customerNo)" it checks the cache and the get it from there if it's there. That is the theory.
However when using Func predicate it does not find the item, but when using the Expression version it does?
My question is how do you use "Expressions" with a Where clause on a list?
The other solution would be to have a method for each search, e.g. "myservice.GetCustomer(etc..) or myservice.GetOrders(etc..) instead of generic
myservice.GetAll(); Which means adding many methods to the interface.
mycode:
public interface IGenericRepository
{
IList<T> GetAll<T>() where T : class;
IList<T> Find<T>(Func<T, bool> predicate) where T : class; //I use this so that I could use the predicate in an where clause against a list.
etc....
}
In my repository I have something like:
public IList<T> Find<T>(Func<T, bool> predicate) where T : class
{
List<T> models = GetCachedModels<T>().ToList();
var result= models.Where(predicate).ToList(); --Does not work!!! tried also with(expression.Compile()).ToList(); !!still no results!!!!
return result;
}
internal IList<T> GetCachedModels<T>() where T : class
{
IList<T> models;
Type typeParameterType = typeof(T);
string cacheName = string.Format("{0}Cache", typeParameterType.Name);
object cacheView = DbCache.Get(cacheName);
if (cacheView == null)
{
models = Set<T>().ToList();
DbCache.Add(cacheName, models, DateTime.Now.AddHours(1));
}
else
{
models = (IList<T>)cacheView;
}
return models;
}
//below method works but cannot use cache!!!!
public IList<T> Find<T>(Expression<Func<T, bool>> predicate) where T : class
{
return Set<T>().Where(predicate).ToList();
}
Expression predicates works only for IQueryable interface. List doesn't inherit it, so if you want to use this expression, you need to return IQueryable in GetCachedModels method, and return Set, so it can query this data. And then you can place it.
Otherwise if you want to cache all items from Set, then you need to pass Func instead of Expression, and then use it in Where extension method, like this - http://dotnetfiddle.net/5YsIy3
UPDATE: I think I've eliminated Unity from the equation. See below for more details.
UPDATE 2: I think I may have eliminated Entity Framework fro the equation. See below for more details.
I have some code that is building a unity container, but it started failing with the above error message out of the blue. It works on other people's machines, but not mine. I deleted the folder the solution was in and refreshed everything from source control to ensure I had nothing that could be causing issues (e.g. duplicate assemblies lying around from a previous build).
Here is part of my code:
public static class UnityBootstrapper
{
public static IUnityContainer Initialise()
{
Trace.WriteLine("UnityBootstrapper.Initialise()");
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
return container;
}
private static IUnityContainer BuildUnityContainer()
{
Trace.WriteLine("UnityBootstrapper.BuildUnityContainer()");
var container = new UnityContainer();
// Other dependencies are registered here
// If the following line is commented out the container is build
// but, obviously, it won't resolve this dependency.
container.RegisterType<IUserAccessEntities, UserAccessEntities>(WebRequestLifetime);
// Other dependencies are registered here
return container;
}
The code apparently fails on the call to BuildUnityContainer(), and I can see that the trace statement I put inside that method is never displayed.
However, if I comment out the line that registers the UserAccessEntities class (which was code generated from Entity Framework 5) then the container is built. Naturally, when I ask for that dependency it can't resolve it, so the code just fails elsewhere.
I've Googled for solutions and they all seem to resolve around generics and moving the generic type from the method to the class level. I can't do that as EF5 creates the class and it puts generics on the properties. e.g
DbSet<MyTable> Tables { get; set; }
The only other thing I can think of is that I've extracted an interface from the EF5 generated class called IUserAccessEntities and the problem could lie there... but I used ReSharper to generate that, so it should be perfectly aligned.
UPDATE
Just to eliminate Unity from the equation, I tried to new up the UserAccessEntities on its own
private static void TestUae()
{
var uae = new UserAccessEntities(); //container.Resolve<IUserAccessEntities>();
Trace.WriteLine("Got the entities: " + uae);
}
And the call to TestUae() fails instead.
UPDATE 2
I created a new class, AlternativeEntities based on the interface I'd previously extracted. When I try to construct that directly it has a new exception: Method 'Set' in type 'AlternativeEntities' from assembly 'UserAccess.Model, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.
However, it does. There are two methods called set, both of which I've given a basic implementation:
public class AlternativeEntities : IUserAccessEntities
{
public DbSet<TEntity> Set<TEntity>() where TEntity : class
{
Trace.WriteLine("public DbSet<TEntity> Set<TEntity>() where TEntity : class");
return null;
}
public DbSet Set(Type entityType)
{
Trace.WriteLine("public DbSet Set(Type entityType)");
return null;
}
// Other methods and properties here.
}
I've ran into a problem while creating an data access layer for my application. I am working with derived entities in Entity Framework. If I try to create an ObjectSet for a derived Entity, I get this Exception:
Blockquote There are no EntitySets defined for the specified entity type 'Type Name'. If 'Type Name' is a derived type, use the base type instead.
I've tried to resolve this problem via Reflection. (if the Entity Type is derived by an Entity Type => get an ObjectSet for the base Type)
I found this: How can I obtain ObjectSet<T> from Entity-Framework at runtime where T is dynamic? but I haven't found how to use Include and Where on the built up ObjectSet.
protected IEnumerable<IDataObject> GetData(Type entityType, Expression<Func<dynamic, bool>> whereClause, Expression<Func<dynamic, dynamic>>[] includes)
{
if (typeof(IDataObject).IsAssignableFrom(entityType.BaseType))
{
return GetData(entityType.BaseType, whereClause, includes);
}
var contextType = this.Context.GetType();
MethodInfo createObjectSetMethod = contextType.GetMethod("CreateObjectSet", new Type[] {}).MakeGenericMethod(entityType);
// Builds up an ObjectSet<EntityType>
dynamic objectSet = createObjectSetMethod.Invoke(this.Context, new object[] { });
dynamic query = objectSet;
if (includes != null)
{
foreach (var include in includes)
{
query = query.Include(include);
}
}
if (whereClause == null)
{
whereClause = (item) => true;
}
query = query.Where(whereClause);
return query.ToList().OfType<IDataObject>();
}
The code runs as intended, as long I don't use the Includes and WhereClause.
When I call this function I dont know the resolved ObjectSet (T-Parameter) at compile time.
Is there any way to use dynamic Expressions in an generic ObjectSet?
Thanks in advance.
The issue looks to be with the
query = query.Include(include);
the var include would be an Expression<Func<dynamic,dynamic>>
The Include Method you access is expecting a string or
Expression<Func<T, TProperty>>
Have you tried to pass the include as a string path? I would expect that to work.
Otherwise you need to construct the expression tree with code
since you cant pass Dynamic objects to
public static IQueryable<T> Include<T, TProperty>(this IQueryable<T> source, Expression<Func<T, TProperty>> path) where T : class;
There is also dynamic linq library to can check out.
System.Linq.Dynamic can be found at following links
http://msdn.microsoft.com/en-US/vstudio/bb894665.aspx
with an intro here http://www.scottgu.com/blogposts/dynquery/dynamiclinqcsharp.zip
This is an easier alternative using text to build expression trees.
Building expressions trees with code is more powerful and flexible but harder.
For a simple repository
public interface ISimpleRepository<T>
{
IApplicationState AppState { get; set; }
void Add(T instance);
void Delete(T instance);
void Delete(Guid rowGuid);
IQueryable<T> GetAll();
T Load(Guid rowGuid);
void SaveChanges();
void Update(T instance);
}
my implementation of the Load() method for specific repository for class Product might look like this:
public Product Load(Guid rowid)
{
return (from c in _ctx.Products where c.id == rowid select c).FirstOrDefault();
}
Now this is assumed when my repository implementation class looks like this:
public class EntityFrameworkProductsProvider : IRepository<Product> ...
What if I had like dozens or hundreds of this small and simple entities that would all use the same behaviour when doing CRUDs (use the same implementation of methods)? I certainly don't want to go and create a class to implement IRepository for each one of them..
I want something like this:
public class EntityFrameworkDefaultProvider<T> : IRepository<T> ...
but I don't know how to implement the LINQ Select expression then because of course I can't write from e in _ctx.T where e... or do I?
I haven't run into this scenario yet because so far I only had very specific entities with custom repository implementation.
Because you tagged your question with entity-framework and entity-framework-4 I assume you are using ObjectContext API. ObjectContext offers method CreateObjectSet<T> which is equivalent of Set<T> on DbContext.
This question is actually duplicate of either:
Generic GetById with DbContext
Generic GetById with ObjectContext
Instead of writing _ctx.Products, you can write _ctx.Set<T>. That takes care of half of the problem (you need to add a generic constraint where T: class to your repository)
Then, if rowid is the object's key, you can use _ctx.Set<T>.Find(rowid) instead of a LINQ query to retrieve by Id.
Alternatively, you can create a base interface IHaveId (or a BaseEntity class, whatever you like) which has the Id property, and then add that as an generic constraint on T, so you can use it in your queries.
If you're using EF 4.1, see the sample generic repository here:
http://www.asp.net/entity-framework/tutorials/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
I know that this is possible in EF4.1 with the DbContext API, where you have a "Set" method on the context that gets you the entity set corresponding to the type T. this way, you could have your repository like this:
public class EntityFrameworkDefaultProvider<T> : IRepository<T> where T:class
{
public T Load(Guid rowId)
{
return _context.Set<T>().Find(rowId);
}
}
one more remark: I think you could use this syntax :
return _ctx.Products.FirstOrDefault(c=>c.id == rowid);
to get the entity you want instead of using the (from... in...). it's clearer (in my opinion) :)
Hope this helps
Could anyone advise me on how they've implemented the use of Function Imports when using the Repository pattern against EF 4.0?
We have a table mapped to a Candidate Entity and also a Function Import off an existing sproc that maps to Candidate. This works great in EF but we're abstracting by use of Repositories which take on their constructor the IObjectSet where T is the POCO entity. However this means I'm unable to get a reference to the function import. The only way I can see of doing this is passing a reference to the ObjectContext to the repositories that need it but this feels like a bit of a design smell to me.
Even though several of our Repositories are extended with custom interfaces we're still faced with the same issue.
public class CandidateRepository : Repository<Candidate>, ICandidateRepository
{
public CandidateRepository(IObjectSet<Candidate> entities)
: base(entities)
{
}
public Candidate GetByEmail(string email)
{
return Entities.SingleOrDefault(c => c.EmailAddress.Equals(email));
}
public bool CandidateExists(string candidateNumber)
{
return Entities.SingleOrDefault(c => c.Number.Equals(candidateNumber)) != null;
}
public Candidate GetByNumber(string number)
{
return Entities.SingleOrDefault(c => c.Number.Equals(number));
}
public Candidate GetMember(string number)
{
return new Candidate(); //This one needs to return from the Function Import
}
}
Any advice greatly appreciated.
To solve your problem directly you can cast entities to ObjectSet<T> and use entites.Context property to get ObjectContext.
public Candidate GetMember(string number)
{
var objectSet = Enities as ObjectSet<Candidate>;
if(objectSet == null) throw new Exception("Oh, it's not EF IObjectSet implementation");
return objectSet.Context.MyCustomFunction(string number);
}
As you can see this code relies on specific IObjectSet implementation which is not good at all.
The better idea is to create repositories for aggregate roots only rather then for each table. So it will be more natural to pass ObjectContext to repository ctor.
I have went down this route and i have experienced that it is less of a pain when you pass in an interface implementation of the ObjectContext to your repository. The interface implementation should have some way of calling the function. So when you pass in the concrete implementation of the ObjectContext everything should work fine.