how to convert the <T> to its base type for generic method?
I have a generic CRUD class to perform add, delete, select, create to my entity objects.
one of them - Message has two derived classes - order_message , and report_message.
My problem is that in my generic class, I need an objectset to perform crud ops, but objectset does not accept a derived class type, it only accept开发者_高级运维 base class type.
This is the error I received:
There are no EntitySets defined for the specified entity type 'CustomerWebPortal_Entities.Order_Message'. If 'CustomerWebPortal_Entities.Order_Message' is a derived type, use the base type instead.
I tried use typeof(T).BaseType to replace T, and of cause was not working.
How should I correct this?
This is the overview of the generic class:
public abstract class baseCrudDao<T> : ICrudDao<T> where T : class
{
private System.Data.Objects.ObjectContext _context;
private System.Data.Objects.ObjectSet<T> _entity;
public baseCrudDao()
{
_context = new CustomerWebPortalEntities();
_entity = _context.CreateObjectSet<T>(); <-- error at here, only accept base type
}
Well I finally had a chance to write a prototype as suggested. I think that something like this would work but I haven't tested it. Now all of your crud methods can be defined against the IObjectSet<>
member.
public class Crud<EntityType> where EntityType : class
{
private readonly ObjectContext Context;
private readonly IObjectSet<EntityType> Entities;
public Crud(ObjectContext context)
{
Context = context;
Type BaseType = GetBaseEntityType();
if (BaseType == typeof(EntityType))
{
Entities = Context.CreateObjectSet<EntityType>();
}
else
{
Entities = (IObjectSet<EntityType>)Activator.CreateInstance(typeof(ObjectSetProxy<,>).MakeGenericType(typeof(EntityType), BaseType), Context);
}
}
private static Type GetBaseEntityType()
{
//naive implementation that assumes the first class in the hierarchy derived from object is the "base" type used by EF
Type t = typeof(EntityType);
while (t.BaseType != typeof(Object))
{
t = t.BaseType;
}
return t;
}
}
internal class ObjectSetProxy<EntityType, BaseEntityType> : IObjectSet<EntityType>
where EntityType : BaseEntityType
where BaseEntityType : class
{
private readonly IObjectSet<BaseEntityType> Entities;
public ObjectSetProxy(ObjectContext context)
{
Entities = context.CreateObjectSet<BaseEntityType>();
}
public void AddObject(EntityType entity)
{
Entities.AddObject(entity);
}
//TODO: implement remaining proxy methods
public IEnumerator<EntityType> GetEnumerator()
{
return Entities.OfType<EntityType>().GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public Type ElementType
{
get { return typeof(EntityType); }
}
public Expression Expression
{
get { return Entities.OfType<EntityType>().Expression; }
}
public IQueryProvider Provider
{
get { return Entities.Provider; }
}
}
One work-around will be to use two generic type parameters (on base class) such as
public abstract class baseCrudDao<T, U> : ICrudDao<T> where U : class, T: U
{
...
public baseCrudDao()
{
_context = new CustomerWebPortalEntities();
_entity = _context.CreateObjectSet<U>(); <-- error at here, only accept base type
}
...
}
Use Message in place of U. If you have many types and not all have inheritance relationships then constraint T:U won't work and you need to perhaps use T:class constraint. I will also suggest that you create another skeleton base class to be used for other types such as
public abstract class base2CrudDao<T> : baseCrudDao<T, T>
so that you don't have to specify U parameter for classes that don't have inheritance relationship.
精彩评论