Entity Framework: context.CreateObjectSet<T> derived entity issue - c#

I am using EF6 ObjectContext generator which means our entities inherit from EntityObject.
I am trying to implement a generic repository for simple CRUD operations but I've got a specific problem when it comes to derived entities. I can't get the right code to handle this generically despite many different attempts!
public DataRepository(ObjectContext context)
{
_context = context;
_objectSet = _context.CreateObjectSet<T>();
Type baseType = GetBaseEntityType();
if (baseType == typeof(T))
_objectSet = _context.CreateObjectSet<T>();
else
// how to create the objectset here?
// I have tried the below but it blows up at runtime with an invalid cast exception
_objectSet = (IObjectSet<T>)Activator.CreateInstance(typeof(ObjectSetProxy<,>).MakeGenericType(typeof(T), baseType), context);
}
I have read through
Entity Framework: ObjectSet and its (generics) variance
but this seems to be targeted at getting an ObjectQuery rather than an ObjectContext. Any help greatly appreciated. :o)
Update: If there aren't any clean solutions for this are there any workarounds people can think of? I considered an auto-generated list of derived entities with a check on the type etc but as it's a generic repo it must ultimately use IObjectSet, so the following lines fail anyway with an invalid cast _objectSet = (IObjectSet) _context.CreateObjectSet();

This might be of interest. I don't know if the behaviour was changed in version 6 though.

I've ended up sorting this out myself. Passing in the base and derived entities (we only ever have one level of inheritance). Here's a flavour of how it looks in case anybody else needs a pointer ....
public class DataRepository : IRepository
where TBaseEntity : EntityObject
where TDerivedEntity : TBaseEntity
{
protected static Ent ctx{get{return DBContextManager.GetDBContext();}}
private ObjectContext _context;
private readonly ObjectSet<TBaseEntity> _objectSet;
public DataRepository(): this(DBContextManager.GetDBContext()){}
public DataRepository(ObjectContext context)
{
_context = context;
_objectSet = _context.CreateObjectSet<TBaseEntity>();
}
private ObjectQuery<TDerivedEntity> TypedObjectSet
{
get
{
return _objectSet.OfType<TDerivedEntity>();
}
}
public IEnumerable<TDerivedEntity> Find(Expression<Func<TDerivedEntity, bool>> predicate)
{
return TypedObjectSet.Where(predicate);
}
public TDerivedEntity Single(Func<TDerivedEntity, bool> predicate)
{
return TypedObjectSet.Single(predicate);
}
// etc etc

Related

Cannot figure out C# generics with multiple and contained generic objects

I am trying to use the template pattern and C# generics to write a utility that will list the entities in the database for any DbSet within Any DbContext. I presume I need three generics:
public class lister<TDbSet, TContext, TEntity>
where TDbSet : DbSet<IPEntity>
where TContext : DbContext
were TEntity : IPEntity
(IPEntity is an abstract base class for all of our entity classes.) Everything seems to be happy except for trying to write a LINQ expression to get the result set. Since "TDbSwt" is actually a MEMBER of TContext, I cannot figure out if LINQ will let you do something like:
from x in TContext.TDbSet select x
It certainly does not like THAT line, whether or not I prefix TDbSet with TContext or not.
Anyone know how I could set this up? right now I have separate (very small, but still one for each entity) class for the entity and LINQ specifics, but as we grow from dozens to hundreds to perhaps thousands of entities, I would like to find a more compact and elegant solution.
Thanks.
from x in TContext.TDbSet select x
There's two reasons this won't work:
TContext is a type, but the member you're trying to call on it isn't static, so you need an instance of TContext
TDbSet is also a type. Just because TContext happens to have a member with the same name (or even the same type) as TDbSet doesn't mean you can start using TDbSet as a member name rather than a type.
What you want is probably something like this:
public class lister<TEntity>
where TEntity : IPEntity
{
private DbContext _context;
private DbSet<TEntity> Set
{
get { return _context.Set<TEntity>(); }
}
public lister(DbContext context)
{
_context = context;
}
}
Now within that class you can write:
from x in Set select x
And it will work as you expected.
Alternatively, you might want lister to itself instantiate the context. This is less likely to be what you should be doing, but I can't be sure without seeing your overall design. In this case, you'd instead want:
public class lister<TEntity, TContext>
where TEntity : IPEntity
where TContext : DbContext, new()
{
private TContext _context;
private DbSet<TEntity> Set
{
get { return _context.Set<TEntity>(); }
}
public lister()
{
_context = new TContext();
}
}
There may be some variation. You may want to pass in or instantiate your context from another method rather than the constructor, for example.
As you can see you cannot use a dynamic name for a member with generics. This would not be statically verifiable (like the C# type system likes to be).
Fortunately, DbContext has a member Set<T>().
public class lister<TDbSet, TEntity>
where TDbSet : DbSet<TEntity>
were TEntity : IPEntity
static DbSet<TEntity> Read(DbContext ctx) { return ctx.Set<TEntity>(); }
As you can see the context does not need to be generic.

InvalidCastException from Entity.DynamicProxies.MyEntityClass to Entity.DbSet`1[MyEntityClass]

I am having difficulty understanding why I am getting an InvalidCastException
Here is the error message that I'm getting:
Unable to cast object of type 'System.Data.Entity.DynamicProxies.Man_58184D79075BC811252680D7866D3D69D0C46FD038D3B123A5E3B102E1FC77A2' to type 'System.Data.Entity.DbSet`1[ConsoleApplication1.Man]'.
Man is the name of the entity class being passed to TEntity
I've marked the location of the error with a comment in the code.
The purpose of this repository class is to hold a given DbContext and DbSet, and call its methods to delete records and/or display all records of the given DbSet.
public class Repository<TEntity> where TEntity : class
{
private DbContext dbContext;
private DbSet<TEntity> dbSet { get; set; }
public Repository(DbContext dbContext)
{
this.dbContext = dbContext;
this.dbSet = this.dbContext.Set<TEntity>();
}
public void Delete(int id)
{
TEntity entity = dbSet.Find(id);
dbSet.Remove(entity);
dbContext.SaveChanges();
}
public void DisplayAll()
{
IQueryable Query = from item in dbContext.Set<TEntity>()
where true
select item;
foreach (DbSet<TEntity> x in Query) //InvalidCastException
{
// print entity fields to console here.
}
}
}
These are the lines in my main program that I use to create a Repository Object:
TestDataBaseEntities is the type of DbContext object I use to refer to my entity model.
class Program
{
static void Main(string[] args)
{
int myID;
var dbEntities = new TestDatabaseEntities();
Repository<Man> ManTracker = new Repository<Man>(dbEntities);
ManTracker.Display(); // exception thown in this method.
Console.WriteLine("Choose ID to delete from Men list");
myID = int.Parse(Console.ReadLine());
ManTracker.Delete(myID);
ManTracker.Display();
Console.ReadLine();
}
}
I think I figured out the answer. I was using the wrong type in the for each statement.
Instead of doing DbSet I should have used TEntity instead.
But this is misleading because even though i'm able to typecast to TEntity, I would need to have code that prints the fields of the TEntity object, and TEntity doesn't have access to the fields I need to print. Instead of using a separate repository class, I think i should use an interface that defines a function called display, and gets implemented by each entity class somehow without modifying the auto-generated code from creating the model from the database. Perhaps by creating classes that inherit from the entity classes, and then implement the interface. I had the thought to do it this way because to keep things object-oriented, it seemed to make sense to me that an object shouldn't rely on another object to display its contents to the user, it should display them itself.

Generic Repository Pattern with UnitOfWork Pattern

I am trying to implement a generic repository pattern. I found this site which I think its well explained.
http://www.tugberkugurlu.com/archive/generic-repository-pattern-entity-framework-asp-net-mvc-and-unit-testing-triangle
My purpose is to save the developers some time and keystrokes and I know this will help me.
So I have 2 questions:
1. Is this a good approach or not, will I have some problems in the future?
2. How can I combine it with Unitofwork pattern?, I cant create an instance of the abstract class of course, so the following code its invalid.
public class UnitOfWork : IDisposable
{
#region Private fields
private readonly MyCompanyContext _context = new MyCompanyContext();
private GenericRepository<MyCompanyContext, Task> _taskRepository;
public GenericRepository<MyCompanyContext, Task> TaskRepository
{
get
{
return _taskRepository ??
(_taskRepository = new GenericRepository<MyCompanyContext, Task>());
}
}
namespace MyCompany.DAL.Repository
{
public interface IGenericRepository<T> where T : class
{
IQueryable<T> GetAll();
IQueryable<T> FindBy(Expression<Func<T, bool>> predicate);
void Add(T entity);
void Delete(T entity);
void Edit(T entity);
void Save();
}
public abstract class GenericRepository<C, T> :
IGenericRepository<T>
where T : class
where C : DbContext, new()
{
private C _entities = new C();
public C Context
{
get { return _entities; }
set { _entities = value; }
}
public virtual IQueryable<T> GetAll()
{
IQueryable<T> query = _entities.Set<T>();
return query;
}
public IQueryable<T> FindBy(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
{
IQueryable<T> query = _entities.Set<T>().Where(predicate);
return query;
}
public virtual void Add(T entity)
{
_entities.Set<T>().Add(entity);
}
public virtual void Delete(T entity)
{
_entities.Set<T>().Remove(entity);
}
public virtual void Edit(T entity)
{
_entities.Entry(entity).State = System.Data.EntityState.Modified;
}
public virtual void Save()
{
_entities.SaveChanges();
}
}
}
There are several opinions regarding repositories, but after trying various repository implementations in production for couple years myself, I agree with Ayende's opinion, that repository, especially generic, is redundant abstraction layer.
I liked very much this course:
http://www.pluralsight-training.net/microsoft/Courses/TableOfContents/linq-architecture
It walked through most possible solutions and explained goods and bads.
What we're using right now is very thin abstraction over datacontext, just to overcome Linq2Sql testability issues, which are irrelevant in most cases when using EF.
With a lot of effort you might get that working, but I wonder if the effort is really worth it? I've seen implementations like this before, and they really struggle when attempting to manage many-to-many relationships (have a think about how you'd manage that in your scenario).
You are using Entity Framework, an ORM right? ORMs like Entity Framework and nHibernate are designed to abstract the database implementation from application code, so what is the purpose of adding yet another abstraction above it to manage entities at such a granular level? If it's a question of testing, then you can use a mocking framework to mock the context, thus removing the need for an actual database during testing. If however, for architectural or security reasons you are seeking to remove interactions with a db context from your app code, I'd recommend for pragmatism using an implementation of the command pattern over the top of the entity framework. I've needed to do this on a larger scale enterprise (banking) application where for security reasons (rightly or wrongly) we were absolutely not allowed to have a db connection in our application code.

Exposing EntityFramework 4 entities as IList instead of IObjectSet

I have a 'Customer' POCO entity within my Entity Framework 4 project. I want to expose my Customer entities to my upper layers as a generic list rather than an ObjectSet.
I have an IUnitOfWork interface which looks as follows:
public interface IUnitOfWork
{
string Save();
IList<Customer> Customers { get; }
}
Down at my Entity Framework DAL (which implements the above interface) I have the following:
public class EntityContainer : ObjectContext, IUnitOfWork
{
private IObjectSet<Customer> _customers;
public IList<Customer> Customers
{
get
{
if (_customers == null)
{
_customers = CreateObjectSet<Customer>("Customers");
}
return _customers.ToList<Customer>() ;
}
}
}
However the 'CreateObjectSet("Customers")' line doesn't work. Every time I try to add a new 'Customer' nothing happens. Interestingly, if I revert to using an IObjectSet then the code works. For example:
public interface IUnitOfWork
{
string Save();
IObjectSet<Contact> Contacts { get; }
}
public class EntityContainer : ObjectContext, IUnitOfWork
{
private IObjectSet<Customer> _customers;
public IObjectSet<Customer> Customers
{
get
{
if (_customers == null)
{
_customers = CreateObjectSet<Customer>("Customers");
}
return _customers;
}
}
}
IQueryable also works, but I cannot get IList to work and I have no idea why. Anyone any ideas?
#
A correction to the original question. Using IQueryable doesn't work, nor does IEnumerable. This is because the Customer repository needs to provide 'Add' and 'Delete' methods to add/delete from the entity collection (add or remove customer entities in the above example). Neither IQueryable or IEnumerable allow you to add or remove objects; instead, an ICollection or IList must be used. This leaves me back at my original problem. I do not want to expose my collection to the repository as an ObjectSet. I want to use a type which is not tied to the EntityFramework i.e. - I want to use a generic list.
Has anyone any more suggestions? I suspect there's a straightforward way of doing this, but I'm not familiar enough with the framework to figure it out.
You seem to be missing a Repository in all of this. The Repository is usually what handles the conversion from ObjectSet<T> to IList<T> (or, in most cases, IEnumerable<T> or IQueryable<T>).
public class EntityContainer : ObjectContext
{
private IObjectSet<Customer> _customers;
public IObjectSet<Customer> Customers
{
get
{
return _customers ??
( _customers = CreateObjectSet<Customer>("Customers");
}
}
}
public class CustomerRepository
{
EntityContext _context = new EntityContext();
public IQueryable<Customer> FindAll()
{
return _context.Customers;
}
public Customer FindById(int id)
{
return _context.Customers.Single(c => c.Id == id);
}
// And so on.
}
I usually then have my UnitOfWork create the Repositories that should be enlisted in the Unit of Work so that anything done through the repositories is bundled in a single operation.
Keep in mind, that my UnitOfWork only would have two methods. One for getting a repository and another for committing the Unit of Work. All data retrieval is handled by the Repositories.
_customers.ToList() is the culprit. ToList executes the query and copies all the items from that query into a new collection object. this new collection object does not provide the tracking capabilities that ObjectSet has.

Retrieving subclass type in base class?

I am attempting to use the Microsoft enterprise Validation methods to perform validation in my entities. In my base class I have the following method:
public class BaseEntity
{
public bool IsValid()
{
return Validate().IsValid;
}
public ValidationResults Validate()
{
return Validation.Validate<this.GetType()>(this);
}
The problem with this is that even when a subclass of BaseEntity calls IsValid, this.GetType() always returns BaseEntity, not the Subclass's type. I don't want to have to rewrite this code for every entity, as that seems very un-OO like. Is there any other way to do this?
I did have the idea to have a protected variable protected Type _validationType, and in every entity set it to that entity's .GetType value, but it seems like there has to be a better way to do this.
Update
Nevermind apparently. this.GetType() seems to be working as I was hoping. Not sure why it wasn't before.
I also changed my Validate() method to use the following code:
return ValidationFactory.CreateValidator(this.GetType()).Validate(this);
When you use an O/RM mapper such as LINQ to SQL, NHibernate or LINQ to Entities (ADO.NET Entity Framework) I'd go with another approach of validating. I'd keep the entities completely clean of validation (so no BaseEntity.Validate() in there. You can move this validation logic to the ObjectContext (EF) / DataContext (L2S) / Session (NH) and trigger validation during a database submit. Look at the example below for LINQ to SQL:
public partial class NorthwindDataContext
{
public override void SubmitChanges(ConflictMode failureMode)
{
var invalidResults = (
from entity in this.GetChangedEntities()
let type = entity.GetType()
let validator = ValidationFactory.CreateValidator(type)
let results = validator.Validate(entity)
where !results.IsValid
from result in results
select result).ToArray();
if (invalidResults.Length > 0)
{
// You should define this exception type
throw new ValidationException(invalidResults);
}
base.SubmitChanges(failureMode);
}
private IEnumerable<object> GetChangedEntities()
{
ChangeSet changes = this.GetChangeSet();
return changes.Inserts.Concat(changes.Updates);
}
}
In the case your entities are invalid, an ValidationException will be thrown. You can catch that specific exception and iterate the InvalidResults property that you'd define on it.
When you need more information, I advise you to read this article. It also describes how to do this with Entity Framework.
Good luck.
Its very un-OO like for the base class to know anything about the subclasses. This works the way it should work.
If you want to know something about the subclasses, then you need to override this method.
Apart from all that stuff about validation, there's a way to code a baseclass' method to let it know which actual subclass type it is called on.
Well... a way to pretend, at least (without breaking any OO rule, Gabriel). It is very elegant and works perfectly well :
public ValidationResults Validate<TEntity>(this TEntity e) where TEntity : BaseEntity
{
return Validation.Validate<TEntity>(e);
}
A great benefit of the extension method among others... :)
You can make IsValid() and Validate() a virtual method to provide some custom definitions in sub classes.
Moving the type logic out of BaseEntity is cleaner.
public class BaseEntity
{
public bool IsValid()
{
return Validate().IsValid;
}
public ValidationResults Validate()
{
return Validation.Validate(this);
}
}
public class Validation
{
public static ValidatorResults Validator<T>( T entity )
where T : BaseEntity
{
return ValidationFactory.CreateValidator(entity.GetType()).Validate(entity);
}
}

Categories

Resources