31

I want to use IoC with Entity framework and Ninject. I figure I need the Generated Entity classes to implement an interface, ICRUD. There's a walkthrough that shows how to force Entity framework to implement an interface. I followed the directions and my EntityObjectCodeGenerator.cs file indeed shows "ICrud", but doesn't implement the interface. I don't see any subclasses under EntityObjectCodeGenerator.tt as the article says I'm supposed to. I get error

'BugnetMvc.Models.BugNetEntities' does not implement interface member 'BugnetMvc.Services.ICrud.Update()'

UPDATE
The goal is to create a testable, extensible MVC-3 intranet utilizing entity framework that also supports strongly typed Views and partial views. From my small level of experience with Ninject thus far, I believe I need to overload my Controller's constructor with a service for the View itself (Assume CRUD methods available for each interface) and one for each partial view:

E.G.

public HomeController(HomeService homeCrudService, PartialViewService1 partialviewService)

Update2
To be clear and hopefully help others, the code can be implemented as follows:

This is how one can extend Entity

namespace BugnetMvc.Models//ensure namespace matches entity
{
    public partial class Milestone : ICrud<Milestone>//Entity, note the CRUD generic.  This gives us a lot of flexibility working with Ninject
    {
        public bool Create()
        {
            throw new System.NotImplementedException();
        }

        public List<Milestone> Read()
        {
            var milestones = new List<Milestone>();

            var result = from a in new BugNetEntities1().Milestones
                            where a.MilestoneID >= 0
                            select new { a.Milestone1 };

            milestones = result.AsEnumerable()
                                        .Select(o => new Models.Milestone
                                        {
                                            Milestone1 = o.Milestone1
                                        }).ToList();
            return milestones;
        }

        public bool Update()
        {
            throw new System.NotImplementedException();
        }

        public bool Delete()
        {
            throw new System.NotImplementedException();
        }
    }

A sample Mock entity:

namespace BugnetMvc.Services
{
    public class MilestoneServiceMock : ICrud<MilestoneMock>
    {
        public MilestoneServiceMock()
        {

        }

        public bool Create()
        {
            throw new System.NotImplementedException();
        }

        public bool Update()
        {
            throw new System.NotImplementedException();
        }

        public bool Delete()
        {
            throw new System.NotImplementedException();
        }


        List<MilestoneMock> ICrud<MilestoneMock>.Read()
        {
            //string[] mileStones = new string[14];
            List<MilestoneMock> milestoneMocks = new List<MilestoneMock>();
            milestoneMocks.Add(new MilestoneMock("New"));
            milestoneMocks.Add(new MilestoneMock("Assessment"));
            milestoneMocks.Add(new MilestoneMock("Pending Approval"));
            milestoneMocks.Add(new MilestoneMock("Pending Start"));
            milestoneMocks.Add(new MilestoneMock("Planning"));
            milestoneMocks.Add(new MilestoneMock("Dev-In Process"));
            milestoneMocks.Add(new MilestoneMock("Dev-Pending Approval to QA"));
            milestoneMocks.Add(new MilestoneMock("Dev-Pending Move to QA"));
            milestoneMocks.Add(new MilestoneMock("QA-In Process"));
            milestoneMocks.Add(new MilestoneMock("QA-UAT"));
            milestoneMocks.Add(new MilestoneMock("QA-Pending Approval to Prod"));
            milestoneMocks.Add(new MilestoneMock("QA-Pending Move to Prod"));
            milestoneMocks.Add(new MilestoneMock("On-Going"));
            return milestoneMocks;
        }
    }
}
//Global.asax
        internal class SiteModule : NinjectModule
        {
            public override void Load()
            {
                bool MOCKDB = true;
                MOCKDB = false;
                if (MOCKDB)
                {
                    //Set up ninject bindings here.
                    Bind<ICrud<MilestoneMock>>().To<MilestoneServiceMock>();
                    Bind<ICrud<Application>>().To<ApplicationService>();
                }
                else
                {
                    //Set up ninject bindings here.
                    Bind<ICrud<Milestone>>().To<Milestone>();
                    Bind<ICrud<Application>>().To<ApplicationService>();
                }
            }
        }

The need for Read(int Id), may arise, in which case a new interface using the same basic ideas above should do the trick. One could even update ICrud to pass the model type into the methods as well. There's plenty of options. This worked for me, thanks to Jon Skeet for his expert guidance.

P.Brian.Mackey
  • 43,228
  • 68
  • 238
  • 348

4 Answers4

57

Presumably the generated entity classes are partial classes, correct?

If so, you can just add your own partial class files to specify the interfaces to be implemented - and to provide any actual implementation methods you need. I suspect that will be a lot simpler than changing what gets generated.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    Don't agree. He would like it for "the generated entity classES", this solution could be a maintenance disaster...if you see what I mean...you probably do ;) – Youp Bernoulli Feb 18 '11 at 20:30
  • 1
    @Joep: It depends what's required, and how many classes there are. If it's *just* a case of adding the interface declaration, it's easy to do that for all entity classes in a single file, like I do for protocol buffers here: http://code.google.com/p/protobuf-csharp-port/source/browse/trunk/src/ProtocolBuffers/DescriptorProtos/PartialClasses.cs If it takes more code than that, it could become worth using T4. – Jon Skeet Feb 18 '11 at 20:33
  • There's alwyas a trade off...somewhere. If it's for all the classes (I had such a requirement) and maybe future classes, a base class which implements the everywhere needed Interface would be nice. If it's only for a few specific classes the hand-made partial class would be the way to go. – Youp Bernoulli Feb 18 '11 at 20:48
  • You already did exactly what I was trying to do. The idea to use an interface AND a generic for this is GENIUS!!! THANK U – P.Brian.Mackey Feb 18 '11 at 21:41
  • 1
    Try this instead: http://code.google.com/p/protobuf-csharp-port/source/browse/src/ProtocolBuffers/DescriptorProtos/PartialClasses.cs – Jon Skeet Mar 16 '12 at 21:32
  • Modifing the T4 template to implement and initialize the partial classes, and adding/coping the T4 to produce Interfaces instead of partial really is a trivial operation.. you get the added benefit of using the generated interfaces in models and views as well. – Brett Caswell Sep 19 '14 at 17:24
  • 1
    @BrettCaswell: I guess it depends on your experience. Never having done anything with T4 before, I think it would take me a lot longer than adding the partial classes :) – Jon Skeet Sep 19 '14 at 17:25
  • ah.. sort of.. I mean my T4 templates would work with any of your database-first implementations, you would just need to specify your EDMX file name (location).. it's 99% decoupled and reuseable (unless you want to generate them in different namespaces).. it's so simple It should be it's own EF Project file. – Brett Caswell Sep 19 '14 at 17:40
  • @JonSkeet, I wanted to add that your answer is the best solution for pattern-based implementations.. that is, when there are similiar columns (name datatype) across multible tables: like dateModified, dateCreated, isEnabled, name. My team uses 'ILookup' as a naming convention for those interface implementations on the partial classes.. – Brett Caswell Sep 22 '14 at 18:59
8

The interface implementation is to be added to the T4 template while modifying it. It is not shown in the screenshots but it is mentioned as item 13 that the user has to implement the IValidate interface in the T4 template. Once the implementation is provide, the generated classes would have those implementations too.

User: notes that the generated classes (under the .tt file) implement the IValidate interface as expected

amit_g
  • 30,880
  • 8
  • 61
  • 118
  • 1
    This is a fantastic answer. I don't understand for the life of me why it doesn't have more upvotes. – KSwift87 Apr 06 '15 at 19:16
  • This would be the correct answer, right? Why would you make a bunch of partials if you didn't have to? The EF templates are base templates which can happily be edited to add more functionality! – Josh M. Jul 29 '15 at 12:15
1

What about making a base class (outside the EntityModel) that all entities derive from (a simple modification in the T4 template file) and implementing the interface in the base class once? It works perfect for me.

Youp Bernoulli
  • 5,303
  • 5
  • 39
  • 59
0

It was a while ago, but I did this using a T4 template... see this post: EntityFramework trigger like Auditing

Nix
  • 57,072
  • 29
  • 149
  • 198