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.
Related
I'm trying to create a simple data access class which acts as a library to return various entities. All my entity classes are generated via the Linq-to-SQL mapper in VS 2013, and all of them can be returned from the dataContext via Find(primary id)
I'd like to just define generic Find, Delete, Update etc without having to repeat it for every table/object but I don't want to create a Repository pattern.
How do I create a generic method that works regardless? This is what I have and of course it says T not defined, but I thought we could create generic methods in non-generic classes, so what am I doing wrong?
What I'd like to do is something like
var c = DAL<Customer>.Find(id)
var e = DAL<Employee>.Find(id)
... etc.
The code I attempted to write is
public class DAL
{
private string _key;
private DataContext _context = null;
//private DbSet<T> _table = null;
public DAL(string key)
{
_key = key;
_context = new DataContext();
}
public void Dispose()
{
_context.Dispose();
}
public DbSet<T> Find<T>(int id)
{
var d = _context.Set<T>();
//return d.Find(id);
}
}
I'm kind of lost... I do not want to define
public class DAL<T> where T:class
which ties each DAL to a type
This is the first time I'm venturing into generic nethods so any help appreciated
You can specify a generic method of a class, but you will need to use a constraint:
public class DAL
{
// .... previously written code
public DbSet<T> Find<T>(int id) where T : class
{
return _context.Set<T>();
}
}
You will also have to call it like this:
var dal = new DAL();
var data = dal.Find<Customer>(1);
Also note, that your code has a number of problems, you define a dispose method, but you don't implement the IDisposable interface, you're not actually returning anything from the method, etc..
Note: for all intents and purposes, this is still a repository pattern.
Something like this should work:
public T Find<T>(int id) where T : class
{
return context.Set<T>().Find(id);
}
I'm using the Entity Framework with a large database (made up of more than 200 tables).
Trying to create a generic method that returns the DbSet<T> of a specific table T (i.e. class, which can be TableA).
The entity class that was (automatically) created using the entity data model looks like so:
public partial class sqlEntities : DbContext
{
public virtual DbSet<TableA> TableA { get; set; }
public virtual DbSet<TableB> TableB { get; set; }
public virtual DbSet<TableC> TableC { get; set; }
... // other methods
}
My main class is like this
public class TableModifier
{
// Should return first 10 elements from a table of that type T
public IQueryable<T> GetFromDatabase<T>() where T : EntityObject
{
try
{
using (sqlEntities ctx = new sqlEntities())
{
// Get the DbSet of the type T from the entities model (i.e. DB)
DbSet<T> dbSet = ctx.Set<T>();
return dbSet.Take(10);
}
}
catch (Exception ex)
{
// Invalid type was provided (i.e. table does not exist in database)
throw new ArgumentException("Invalid Entity", ex);
}
}
... // other methods
}
I have to set a constraint where T : EntityObject on T to be within the EntityObject bounds. If there was no such constraint then the DbSet<T> dbSet would complain (i.e. T must be a reference type) that it might be getting more than it expects in terms of types (based on this).
The problem occurs when I try to actually call the method with a specific type.
[TestMethod]
public void Test_GetTest()
{
TableModifier t_modifier = new TableModifier();
// The get method now only accepts types of type EntityObject
IQueryable<TableA> i_q = t_modifier.GetFromDatabase<TableA>();
}
It gives an error:
There is no implicit reference conversion from 'TableMod.TableA' to
'System.Data.Entity.Core.Objects.DataClasses.EntityObject'.
How can I (cast?) the TableA type as an EntityObject if I know it exists for that entity model?
Though this is incorrect syntax (and logic) this is what I'm after:
t_modifier.GetFromDatabase<(EntityObject)TableA>();
How can I define the TableA (along with all the other 200 tables) type to be a part of EntityObject?
A potential solution
Turns out my constraint was too specific, all I needed to change was from where T : IEntity to
where T : class
So the T is what the DbSet<T> initially expected, a class type
Saves the trouble of having to add implementations to the 200+ table classes, TableA, TableB, ...
Then of course there's other problems such as changing the return type from IQueryable<T> to List<T> since the IQueryable would otherwise be returned outside of the scope of DbContext (i.e. sqlEntities) rendering it useless.
Why don't you try changing your constrain to class instead of EntityObject
public IQueryable<T> GetFromDatabase<T>() where T : class
I had the same requirement and solved it by using the following:
public static void GetEntitiesGeneric<TEntity>()// where TEntity : System.Data.Entity.Core.Objects.DataClasses.EntityObject <-- NO LONGER NEEDED
{
try
{
var key = typeof(TEntity).Name;
var adapter = (IObjectContextAdapter)MyDbContext;
var objectContext = adapter.ObjectContext;
// 1. we need the container for the conceptual model
var container = objectContext.MetadataWorkspace.GetEntityContainer(
objectContext.DefaultContainerName, System.Data.Entity.Core.Metadata.Edm.DataSpace.CSpace);
// 2. we need the name given to the element set in that conceptual model
var name = container.BaseEntitySets.Where((s) => s.ElementType.Name.Equals(key)).FirstOrDefault().Name;
// 3. finally, we can create a basic query for this set
var query = objectContext.CreateQuery<TEntity>("[" + name + "]");
// Work with your query ...
}
catch (Exception ex)
{
throw new ArgumentException("Invalid Entity Type supplied for Lookup", ex);
}
}
The code was taken from Using Generics for Lookup Tables in Entity Framework and adapted for EF 6 using the DbContext (first part of the method where the objectcontext is extracted from the dbcontext
Hope it helps
I don't know how you have created your model, and thus how your entities look like. But, if it's Code First, the entity classes don't inherit from a common base class, so you cannot add a type constraint to your generic.
I don't recommend using a base class to be able to specify a constraint. It's much better to do it using an interface. An empty interface will allow you to specify a constraint without having to change your classes at all.
So, what you can do is define an interface like this:
public interface IEntity {};
And then:
implement it in all classes, which can be done in partial classes files, modifying a T4 template or in some other way depending on how your model looks like
use it to specify the generic type constrain with where IEntity
This is the cleanest way to do it, without any interference to your classes.
Issue
I suppose your TableA class doesn't implement EntityObject. That's why you're getting this error. To solve this you can have an abstract class/interface which will be base for all context entities (i.e. IContextEntity which will have unique Id definition):
public class TableA : IContextEntity
{
...
}
Then same method but with new interface instead of EntityObject and you can mock/test it easily
public IQueryable<T> GetFromDatabase<T>() where T : IContextEntity
{
...
}
Usage(Tests)
Second important thing is the way you want to use this method. In case of Entity Framework context it is really important to have separation between integration and unit tests. In code you provided you're trying to reach database which means that this test will be integration:
using (sqlEntities ctx = new sqlEntities()) // This will open a DB connection
Connecting to a databases or external sources is usually a bad practice unless you know what you do and this is exactly it. If you just need some fake/dummy data to perform an action on it - use Stubs.
For any future googlers, my colleague and I just hacked this out in Visual Basic (EF 6 version). It works for our use case of simply getting a list back out but will probably work for the other use cases. No try catch or checking in this one.
Private Class getList(Of T As Class)
Public Shared Function getList() As List(Of T)
Using ctx As New MVPBTEntities()
' Get the DbSet of the type T from the entities model (i.e. DB)
Dim dbSet = ctx.Set(Of T)()
Return dbSet.ToList
End Using
End Function
End Class
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
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.
I have the following fake repository that I use for unit testing. How would I implement the Attach(T entity) method in this repository?
(In my real repository, the Attach(T entity) method is used to attach an object to my Entity Framework 4 data context).
public class FakeRepository<T> : IRepository<T> where T : class, new()
{
private static List<T> entities = new List<T>();
public IQueryable<T> Entities
{
get { return entities.AsQueryable(); }
}
public T New()
{
return new T();
}
public void Create(T entity)
{
entities.Add(entity);
}
public void Delete(T entity)
{
entities.Remove(entity);
}
public void Attach(T entity)
{
//How to implement Attach???
}
public void Save()
{
//Do nothing
}
public void Dispose()
{
return;
}
}
To answer this, you have to ask yourself "what is the purpose of "Attach?" You probably know that the point is to tell the repository "this object is persisted in the database but you aren't currently tracking it; I have made updates to it and I want you to commit them when I tell you to submit your changes."
Thus, to test that Attach is working properly, you should maintain a collection of attached objects and add an entity to this collection when it is passed a parameter to Attach.
So, the simplest implementation would be
entities.Add(entity);
but you could consider something more fine-grained. Note that you need to expose a method that lets you assert that the entity was successfully attached (in EF4 you can use ObjectStateManager.TryGetObjectStateEntry).
get rid of the static word on the entities member. Now just do
enitities.Add(entity)