First, spec. We use MVC5, .NET 4.5.1, and Entity framework 6.1.
In our MVC5 business application we have a lot of repetitive CRUD code. My job is to "automate" most of it, which means extracting it to base classes and making it reusable. Right now, I have base classes for controllers, view models and EF6 entity models.
My abstract base class that all EF6 entities inherit:
public abstract class BaseEntity<TSubclass>
where TSubclass : BaseEntity<TSubclass>
{
public abstract Expression<Func<TSubclass, object>> UpdateCriterion();
}
UpdateCriterion method is used in AddOrUpdate method of database context. I have a generic parameter for subclasses because UpdateCriterion needs to return lambda expression that uses exact subclass type, not an interface or base class. An extremely simplified subclass implementing this abstract base class would look like this:
public class Worker : BaseEntity<Worker>
{
public int ID { get; set; }
public int Name { get; set; }
public override Expression<Func<Worker, object>> UpdateCriterion()
{
return worker => worker.ID;
}
}
After that, in SaveOrUpdate action of my base controller, I would have code like this:
public ActionResult Save(TViewModel viewModel)
{
if (ModelState.IsValid)
{
var entityModel = viewModel.ConstructEntityModel();
db.Set<TEntityModel>().AddOrUpdate<TEntityModel>(entityModel.UpdateCriterion(), entityModel);
db.SaveChanges();
}
}
Thanks to that, subclasses of the base controller don't need to implement Save method themselves, as they did before. Now, all of this works, and it actually works really well despite the funky syntax (I mean, class BaseEntity<TSubclass> where TSubclass : BaseEntity<TSubclass>, seriously?).
Here comes my problem. For most of the entities field ID is the key, but for some it isn't, so I can't generalise properly with a superclass implementation. So for now, every entity subclass implements it's own UpdateCriterion. But, since for most (90%+) entities e => e.ID is the correct implementation, I have a lot of duplication. So I want to rewrite the entity base class to something like this:
public abstract class BaseEntity<TSubclass>
where TSubclass : BaseEntity<TSubclass>
{
public virtual Expression<Func<TSubclass, object>> UpdateCriterion()
{
return entity => ((dynamic)entity).ID;
}
}
The intention is to provide default implementation that uses ID as key, and allow subclasses to override it if they use a different key. I can't use an interface or a base class with ID field because not all entities have it. I thought I'd use dynamic to pull out ID field, but I get following error: Error: An expression tree may not contain a dynamic operation.
So, any idea on how to do this? Would reflection work in base UpdateCriterion?
No, you cannot use dynamic in a Linq to Entities query.
But you can build the Lambda Expression at runtime.
public virtual Expression<Func<TSubclass, object>> UpdateCriterion()
{
var param = Expression.Parameter(typeof(TSubclass));
var body = Expression.Convert(Expression.Property(param, "ID"), typeof(object));
return Expression.Lambda<Func<TSubclass, object>>(body, param);
}
If the TSubclass type does not have an ID property Expression.Property(param, "ID") will throw an exception.
Additionally you could use the MetadataWorkspace from your entity model to get the Primary Key column for TSubclass.
If you are defining the BaseEntity class, you could add a virtual read only property that returns the actual ID property. I beleive EF treats read only properties as "computed", so they are not stored to the db.
public abstract class BaseEntity<TSubclass> where TSubclass : BaseEntity<TSubclass>
{
public abstract object ID { get; }
public virtual Expression<Func<TSubclass, object>> UpdateCriterion()
{
return entity => entity.ID;
}
}
public partial class Foo : BaseEntity<Foo>
{
public Int32 FooId { get; set; }
public override object ID { get { return FooId; } }
}
Just a thought - I only tried compiling in LinqPad and checking the value of a call to UpdateCriterion. :)
Take a look at this answer. It uses reflection to get the ID Property. I think it solves your problem:
public static object GetPropValue(object src, string propName)
{
return src.GetType().GetProperty(propName).GetValue(src, null);
}
Then you replace your lambda expression by
return entity => GetPropValue(entity, "ID");
I've not tested, since I have no code fully working to test it. If it works please let us know.
Related
I admit that a large part of my trouble with this must stem from simple lack of understanding around a few of the components involved in the solution. I'm not exactly "new to" Entity Framework, code-first, nor generic types, but the inner workings of all three are still mysterious enough to me that this is giving me fits.
I have a code-first project in which I have separated-out "model" classes from "service" classes, with generalizations in both. I am NOT using the full Repository Pattern, for a variety of reasons. For most of what I am doing, the structure I have in place is working beautifully -- I understand it and it seems quite clean.
But there is one area where I am running into problems, and that is being able to pass one of my model class types as a generic parameter to an instance of a generic service object, given a string path/name of the model class.
(Background: I need to do this because I "seed" several tables in the database with initialization values from a JSON file. This JSON file contains the names of the model entities. So, at runtime, I need to get that string value, and then feed that as the type to the generic service object that does the database operations.)
Here are the pertinent code snippets:
In BaseEntity.cs I have the top-level interface and a number of abstract classes from which the specific model entities then inherit:
namespace POST.API.Models
{
public interface IEntity
{
int Id { get; set; }
}
public abstract class BaseEntity { }
public abstract class Entity : BaseEntity, IEntity
{
public virtual int Id { get; set; }
}
public abstract class TypeEntity : Entity
{
public TypeDefinition Definition { get; set; }
}
}
In BaseService.cs I have another interface and more abstract classes from which specific model service classes inherit. There is also one concrete class, here, that is generalized for performing an insert operation:
namespace POST.API.Services
{
public interface IEntityService { }
public abstract class BaseEntityService<T> : IEntityService
where T : Models.BaseEntity
{
public T Fetch(int Id)
{
using (var Db = new PostDbContext())
{
return Db.Set<T>().Find(Id);
}
}
public void Create(T Item)
{
if (Item != null)
{
using (var Db = new PostDbContext())
{
DbSet Entity = Db.Set<T>();
Entity.Add(Item);
Db.SaveChanges();
}
}
}
public IEnumerable<T> All()
{
using (var Db = new PostDbContext())
{
return (IEnumerable<T>)Db.Set<T>().ToList();
}
}
}
public abstract class BaseTypeEntityService<T> : BaseEntityService<T>
where T : Models.TypeEntity
{ }
public abstract class BasePropertyTypeEntityService<T> : BaseTypeEntityService<T>
where T : Models.PropertyTypeEntity { }
public abstract class BasePropertyEntityService<T> : BaseEntityService<T>
where T : Models.BaseEntity { }
public class TypeEntityService<T> : BaseTypeEntityService<T>
where T : Models.TypeEntity { }
#endregion
}
I've removed some methods not pertinent to the presentation.
I have some code that then attempts to use these base classes to rummage through the JSON file and insert some rows, thus:
using (PostDbContext Db = new PostDbContext())
{
string JsonString = System.IO.File.ReadAllText(JsonDataFile);
DataSet JsonDataSet = JsonConvert.DeserializeObject<DataSet>(JsonString);
foreach (DataTable Table in JsonDataSet.Tables)
{
Type EType = Type.GetType("POST.API.Models." + Table.TableName);
POST.API.Models.BaseEntity E = (POST.API.Models.BaseEntity)Activator.CreateInstance(EType);
Services.TypeEntityService<EType> S = new Services.TypeEntityService<EType>();
foreach (DataRow Row in Table.Rows)
{
// Set properties of E and call Create method of S
}
}
}
I've clearly misunderstood something fundamental, because that code won't compile. On this line of code:
Services.TypeEntityService<EType> S = new Services.TypeEntityService<EType>();
...I get an error on my references to EType, with the compiler complaining "The type or namespace `EType' could not be found."
So, obviously, that reference, there, cannot be evaluated at runtime. Which, then, makes me wonder how on earth do I do this. All the related topics seem to yield no satisfactory answer -- at least not in a way that makes sense in the context of my own implementation.
You need to create the Services.TypeEntityService<EType> with the Activator, something like below...
Type EType = Type.GetType("POST.API.Models." + Table.TableName);
Type[] typeArgs = { EType };
var generic = typeof(Services.TypeEntityService<>).MakeGenericType(typeArgs);
var S = Activator.CreateInstance(generic);
Well you have a variabl of type System.Type in EType. You cannot use Type instances for generic types. You shouldchange your implementation of Services.TypeEntityService to take runtime Type instances (e.g TypeEntityService(System.Type type)).
Edit: Or actually like the other answer states, use Reflection to build Generic parameters from your Type instance. That makes more sense.
I have generic repository implemented. Problem is my virtual types in the main returned type are null. How to include them in async call?
Here is my type:
public class Translation : Entity
{
public string Text { get; private set; }
public Guid TranslationKeyID { get; set; }
[ForeignKey("TranslationKeyID")]
public virtual TranslationKey TranslationKey { get; set; }
}
Now Here is the method where I want that TranslationKey Entity too in my results but I only get TranslationKeyId.
Method of my service :
public async Task<List<TranslationDto>> ListTanslationsAsync()
{
var translations = await _translationRepository.GetAllAsync().
if (translations != null)
{
return translations.ProjectedAs<List<TranslationDto>>();
}
return null;
}
What to write instead of GetAllAsync()??
What is TranslationDto and how did you implement the repository pattern around EF? In short you might have lazy loading off or you did not call Include but here is more on how you could make your implementation better.
I also have implemented a Repository pattern around EF but have created a generic repository where the methods are generic and not the type. The type itself has an instance of an DbContext and the methods make the corresponding calls on Set so there are no hard coded DbSet instances in the DbContext. Here is an example of what you could use, then you can wire it together using Autofac or some other IoC framework.
public interface IMyGenericRepository
{
TEntity Find<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : class;
IQueryable<TEntity> Filter<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : class;
}
public sealed class MyGenericRepository : IMyGenericRepository
{
private DbContext _dbContext;
public virtual TEntity Find<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : class
{
return _dbContext.Set<TEntity>().FirstOrDefault(predicate);
}
public virtual IQueryable<TEntity> Filter<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : class
{
return DbSet<TEntity>().Where(predicate).AsQueryable<TEntity>();
}
}
You could adapt this to make it return an instance of List and leave out the Dto all together by implementing your access logic in the generic repository. Also you can implement the async/await keywords when necessary or by default.
Now for part 2, getting objects in your object graph.
This can be achieved by using the Include extension to ensure that EF populates part of your graph when it retrieves your objects. This can be done by the caller or you can implement a subclass (inherit) from your generic repository to make the call to Include. The code above could be called like this:
var result = await _genericRepository.Filter<Translation>(add lambda here).Include(x => TranslationKey).ToListAsync();
In short there are lots of possibilities using this pattern, its just a matter of figuring out what you need and where to put it.
I've stumbled upon the need to do this a few times recently with some lower level framework type stuff and I'd like to see if there is a better/cleaner way to accomplish this, i.e. if I'm missing something obvious or clever, like the time I discovered [ThreadStatic] to replace dictionary lookups against thread IDs for associating data with Threads.
I have a base abstract class, lets call it Entity. Every Entity needs to perform a set of initialization actions in the constructor that depends on the actual concrete class being instantiated. Is there a way I can accomplish this without doing a dictionary lookup and calling this.GetType()?
Here is some code similar to what I have now:
public abstract class Entity
{
private static Dictionary<Type, Action<EntityData>> _initActions = new Dictionary<Type, Action<EntityData>>();
private EntityData _data = new EntityData();
protected Entity()
{
_initActions[this.GetType()].Invoke(_data);
}
}
public class Employee : Entity
{
public string Name { get; set; }
}
public class Manager : Employee
{
public List<Employee> Subordinates { get; set; }
}
The Employee constructor and Manager constructor need to initialize their _data fields differently as they are different types. The _initActions collection gets initialized in another method prior to any instances being new'd up, which I don't think has any significance on this discussion.
I want usage of the class to remain as simple as possible for the user of the framework, so I can't use strange hacks like requiring users to override an Init method in each concrete type in some peculiar or unintuitive way.
Generics almost work, in the sense that I could do something like Entity<TEntity> to get a TEntity specific static field to store the init method if I didn't have any inheritance, but inheritance needs to be supported so I would need a dictionary of all init methods for the subclasses of TEntity anyway.
This code runs in some pretty low level database engine type scenarios in tight loops with 1m iterations, so getting rid of the dictionary lookup does provide some significant speedups in certain situations (tested by replacing with a hacky Init override implementation).
Any ideas?
EDIT:
I want to make a few things clear. The entity engine automatically sets up _initAction to do what it needs to to initialize its _data container. The "user" of the library knows nothing about this process and doesn't need to. All I was inquiring about is a way to avoid a dictionary lookup to get type-specific runtime information from a base class, but that may not be possible.
Yes, this is micro-optimization, but we have tested this with real queries and gotten 15-20% query time reductions on some queries that need to instantiate large datasets.
The faster code looked like this:
public class Employee : Entity
{
private static EntityInitializer _initMethod = Entity.GetInitMethod(typeof(Employee));
public string Name { get; set; }
public Employee()
{
_initMethod.Invoke(this);
}
}
This way, the dictionary lookup is done once for the Employee type. It's not horrible, but it requires a) boilerplate in every single class, which I don't like and b) slightly error prone as you have to match up the type parameter with the current class otherwise funky things happen, kind of like when you type in the wrong owner class name for a dependency property in WPF. Kinda sometimes works, but then wierd bugs pop up and its hard to trace back.
What it comes down to is this: is there was a better way to attach arbitrary runtime data to a Type besides using a Dictionary, considering that all these types that will have this data attached to them all implement a common base class?
Could you not just create a ctor that you pass the type to?
protected Entity(Type type)
{
_initActions[type].Invoke(_data);
}
}
public class Employee : Entity
{
private static Type mytype = typeof(Employee);
public string Name { get; set; }
public Employee(): base(mytype)
{ }
}
The lookup is causing performance issues?
Dictionary lookup is 0(1) and few milliseconds.
A program can only have so many classes.
Entity still needs to create the object, create a new EntityData, and run Invoke.
In addition to initialization of the classes that implement Entity.
Why does the type of the sub class effect the way an encapsulated class should be populated?
This seems like a violation of some OO principles to me.
If there is some specialized behaviour for a subclass, then
public abstract class Entity
{
private readonly EntityData data = InitializeData(new EntityData());
protected abstract void InitializeData(EntityData data);
}
seems like a better definition for the base class. The specilased action can be defined in the sub class,
Public class Employee : Entity
{
protected override void InitializeData(EntityData data)
{
// Employee specific implementation here ...
}
}
This requires no Dictionary, lookup or even a switch statement. No static state is required. It means the sub class related code has to be in the sub class but, that is a good thing, that is OO.
If its necessary to preserve more of what you have your could do somthing like,
public abstract class Entity
{
private readonly EntityData data;
protected Entity(Action<EntityData> initializeData)
{
this.data = initializeData(new EntityData());
}
}
public class Employee : Entity
{
public Employee : base(SomeStaticAction)
{
}
}
I really feel like you're overthinking this. Why not just have Entity have an abstract get-only property that needs to be overridden?
public abstract class Entity
{
private static Dictionary<Type, Action<EntityData>> _initActions =
new Dictionary<Type, Action<EntityData>>();
protected abstract EntityData _data { get; }
protected Entity()
{
_initActions[this.GetType()].Invoke(_data);
}
}
public class Employee : Entity
{
public string Name { get; set; }
protected overrides EntityData _data {
get { return new EntityData("Employee Stuff"); }
}
}
public class Manager : Employee
{
public List<Employee> Subordinates { get; set; }
protected overrides EntityData _data {
get { return new EntityData("Manager Stuff"); }
}
}
Alternatively, just have two Init methods.
public abstract class Entity
{
private static Dictionary<Type, Action<EntityData>> _initActions =
new Dictionary<Type, Action<EntityData>>();
private void InitalizeBase() { /* do shared construction */ }
protected abstract void Initalize();
protected Entity()
{
InitalizeBase();
Initalize();
}
}
public class Employee : Entity
{
public string Name { get; set; }
protected overrides Initalize()
{
// Do child stuff
}
}
I have a couple independent objects, each of which has a list of a common object. For instance,
public class Project
{
public IEnumerable<CommentEntry<Project>> Comments{get;set;}
}
public class Sample
{
public IEnumerable<CommentEntry<Sample>> Comments{get;set;}
}
public class CommentEntry<T> where T: class
{
public int TId {get;set;}
public int CommentEntryId{get;set;}
public DateTime TimeStamp{get;set;}
public string Comment{get;set;}
}
Using fluent api of Entity Framework 5, I would like a CommentEntry table for Projects and Requests. So, here is my mapping code:
modelBuilder.Entity<CommentEntry<Project>>()
.Map(m =>
{
m.ToTable("EngineeringProjectComments");
});
modelBuilder.Entity<CommentEntry<Request>>()
.Map(m =>
{
m.ToTable("SampleRequestComments");
});
When I attempt my migration I encounter the following message:
The type CommentEntry`1[Project]' was not mapped. Check that the type has not been explicitly excluded by using the Ignore method or NotMappedAttribute data annotation. Verify that the type was defined as a class, is not primitive, nested or generic, and does not inherit from EntityObject.
I can see the obvious flaw of my attempt to use generics in this context. However, can anyone suggest an alternative to my database table structure, classes code or mapping code that will allow me to share the single, generic type among many classes and have independent tables?
Just use the normal inheritance structure. And, instead of using a specific ID name, like EngineeringProjectId, just use Id.
public class Project
{
public ICollection<ProjectCommentEntry> Comments{get;set;}
}
public class Sample
{
public ICollection<SampleCommentEntry> Comments{get;set;}
}
public class ProjectCommentEntry : CommentEntry {}
public class SampleCommentEntry : CommentEntry {}
public class CommentEntry
{
public int Id {get;set;}
public int CommentEntryId{get;set;}
public DateTime TimeStamp{get;set;}
public string Comment{get;set;}
}
By the way, you can't use IEnumerable for navigation properties in EF, you need a full collection which is why you should use ICollection instead.
Is there a way to specify in type parameters that a parameter is the type of the object instance?
For instance, to illustrate, I have:
public abstract class Model
{
public int Prop1 { get; set; }
}
For my example, I want to have a method that will return a property of the Model passed in (obviously this is a stupid method, but it gets the point across). I can make it work as an extension method:
public static class Extensions
{
public static U Property<T, U>(this T model, Expression<Func<T, U>> property) where T : Model
{
return property.Compile().Invoke(model);
}
}
this way I can have
public class DerivedModel : Model
{
public string Prop2 { get; set; }
}
and do
var myString = new DerivedModel().Property(a => a.Prop2);
This method seems like it should be part of the Model class, and look something like:
public T Property<T>(Expression<Func<ThisDerivedInstanceOfModel, T>> property)
{
return property.Compile().Invoke(this);
}
so that the same call to Property() that the extension method does can execute on an instance of a Model.
I realize that this is kind of bizarre and may simply not be a feature of C#, and the workaround extension method works perfectly well - but I'd much prefer to make this an instance method if possible, since seems 'better' to me.
Is there a way to specify in type parameters that a parameter is the type of the object instance?
Nope. Sorry. There are times when I can see it being useful, but it's not something you can do. I've had similar issues in the past :(