Background:
We have a project with many modules. We’re using EntityFramework 4.2 with FluentAPI (CodeFirst).
There is a central project named Diverto.ORM.EntityFramework.SQLServer which contains partial classes that build the context using the FluentAPI (and which has references to every other project on the solution).
Recently we received a request from the customer to implement many other features and the solution will need several other projects. Some of these projects will come from another system (Human Resources) and some will be created. The core of the existing solution is a Finance system.
We want to enable and disable these new projects (and GUI, business logic and all) “on the fly” using MEF. They will interact as plugins and the main menu from the application will get populated also using MEF.
However we don’t really have a clue on how to enable/disable these modules/projects (new ones and HR ones) because of data that they must share.
Consider this:
– DivertoContext (main context) with DbSet<ClassA> and DbSet<ClassB>.
– PluginContext (from a plugin) with DbSet<ClassC>.
Now, consider that inside the GUI I must have access to data from ClassA, ClassB and ClassC (if the plugin is there).
Solution found! See bellow
HEY, YOU THERE, READ THIS BEFORE THE ANSWER!
I’ve noticed some people checking this out and marking this as favorite or upvoting. Please, bear in mind that this answer dates back to 2012 and EntityFramework has changed a lot since that.
Also, please, please, PLEASE, remember that each project has it’s very own needs. I needed this feature, this way, at that time. Your project might not need this at all, or just some parts of this!
Finally, just to make sure everything is covered up, yes, it’s possible to make this work with EF 6.1 and EF Migrations and it might be possible with other ORM and migration framework as well.
You might need some other interfaces, as one for the migration to load, and properly handle specific plugin migration (don’t mix it with other plugins so try to implement some sort of unique token for each plugin).
Solution found!
Well, I’ll try to explain here since I couldn’t find this elsewhere. This is interesting for people that have to create a single base software that will receive multiple plugins and these plugins must interact with existing data within a single database.
First of all, I’ll be working with Entity Framework with CodeFirst API and all. So if you’re going into this I recomend reading of EntityTypeConfiguration from MSDN and of Code First Fluent API also from MSDN.
Now, let’s understang some things:
First things first
Solution: MEFTest
Projects:
Now, the coding
Inside the Base.ORM project create your Generic Repository interface with methods as you see fit, but the interface is not typed. It will be similar to this:
From now on I’ll just call it IRepository to keep things simple.
I’ll consider one method called Add(T item) for sample coding.
Inside the Base.ORM.EntityFramework.SQLServer create a BaseContext class that inherits from DbContext and that implements IRepository. It should look like this:
You might add a custom IDatabaseInitializer base-implementation here for database versioning. I’ve done it with SQL files winthin a standard folder but this is old coding as EF now supports migrations.
If you’ll still up to handling this manually, remember to set the database to single user mode BEFORE and reverting to multi user mode AFTER. Remember: try…catch…finally will help here because you can revert to multi user inside the finally so even on error there will be no problems left behind.
Inside the SampleApplication project, add:
ClassA (int Id, string Name) and ClassB (int Id, DateTime TestDate).
Inside the SampleApplication.ORM.EntityFramework.SQLServer create your standard context.
I’ll use three classes here with very interesting names: ClassA, ClassB and ClassC.
Both ClassA and ClassB are referenced from this project and it will be like this:
Now the funny part: The plugin will have a method like this:
Of course ClassC is inside the plugin project. You don’t have any reference to it from the main project.
You will have to find this method (Setup) using MEF and of course, interfaces. I’ll just show WHERE to place this and how to make it work =)
Back to the Context class, the OnModelCreating method will be like this:
Usage
Inside your APP you will have just one Context. This context inherits from BaseContext which implements IRepository. With that in mind you need to code your GUI and business layer to use IRepository (from Base.ORM) and the specific class (inside the business-specific dll).
It works!
Well, it’s working here.
I think I’ve shown every relevant part here.
Of course there is more code inside the classes but it’s not the case. I’m trying to show only what you really need to create/implement to get it done.
Don’t forget:
Thanks
Thanks to people from SO and from MSDN that helped my a lot with comments and other posts that I’ve found.
Thanks to Caio Garcia (BR) that helped me with some instructions about other plugin-based systems.
Sample codes (full)
Here follows some sample codes:
FOR THE BASIC ITEMS (solution predefined items)
FOR THE PLUGIN
ON YOUR REGULAR CODE