Reputation: 5869
I have recently been learning MVC3 using Entity Framework 4.3 and Dependancy Injection so I can implement unit tests at a later date. I am now trying to implement some functions I have seen in various examples however I have hit a few issues that seem to stem from my use of dependancy injection and therefore I would like someone to point out where I am going wrong.
My first question is pretty simple; In most MVC3 examples I have seen, the access to the database is done in controllers, but when using dependancy injection I seem to need to refactor this code out to the implemented repository. Is this normal and correct?
My second more indepth issue is dealing with this simple example:
I have this method in my repository class which is pretty much copied from an online example (here). However I get an error regarding the Include
part, and the intellisense does say that the variable needs to be a string. I have tried the original code from the link I mentioned earlier and that works fine, the only major difference between the project is that I am using dependancy injection.
public ExampleUser GetStruContractUser(int id)
{
ExampleUser user = context.ExampleUsers
.Include(i => i.ExampleRoles)
.Where(i => i.UserID == id)
.Single();
return user;
}
Changing the Include
parameter to the following works fine.
public ExampleUser GetStruContractUser(int id)
{
ExampleUser user = context.ExampleUsers
.Include("ExampleRoles")
.Where(i => i.UserID == id)
.Single();
return user;
}
For reference this is my DbContext class that I am using:
public class EFDbContext : DbContext
{
public DbSet<ExampleUser> ExampleUsers { get; set; }
public DbSet<ExampleRole> ExampleRoles { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<ExampleUser>().ToTable("User", "MySchema");
modelBuilder.Entity<ExampleRole>().ToTable("Role", "MySchema");
modelBuilder.Entity<ExampleUser>()
.HasMany(m => m.ExampleRoles)
.WithMany(t => t.ExampleUsers)
.Map(a =>
{
a.MapLeftKey("UserID"); // your PK column name in user table
a.MapRightKey("RoleID"); // your PK column name in role table
a.ToTable("UserRole", "MySchema"); // your join table name
});
}
}
Is this an issue due to my use of dependancy injection or is there something else going on that I am misunderstanding?
If you need more information, please ask and I will try and provide it.
Thanks very much.
Upvotes: 2
Views: 124
Reputation: 10416
Yes, extracting your database layer (repositories / context) and then injecting it into your business layer (controllers) is very normal and a good way future proof your application. What if you ever wanted to change your database ORM from Entity Framework to something else? Having it tightly coupled with your controllers would create a huge headache.
Your second issue, with include
, is unrelated to the dependancy injection.
Include
on a dbset
using lambdas an extension in System.Data.Entity
. You'll need to include that reference if you want to use it.
Upvotes: 1
Reputation: 308
Question 1: Using DI doesn't force you to use a repository pattern, in fact they are not related. It's just a nice way to avoid tightly coupling your controller classes to the database context class, and being able to thus test those classes more easily. Repository gives you the ability to hide the implementation details of how you're accessing the DB, and allows you to switch ORM:s if that were to happen (and it never ever does). Repository relies on you to provide interfaces for your DbContext, and so does using DI.
What you want to do is use your DB through an interface nevertheless, and seeing as you're using DI, you could just inject the reference to the DbContext class in the constructor of your controllers, and let the DI controller do the work for you.
The reason it is preferable to pass in an interface that defines the repository to the Controller over passing an interface that defines your DbContext, is because making an interface of the latter can easily become overly complex, whereas sticking to a repository is much simpler. For simplicity though, I'd start with just using DbContext directly, and then expanding from there.
Question 2:
Include needs to contain the name of the table as a string. So your latter use of Include is correct, and the former isn't.
If I remember correctly, you can do this tho: ".Include(i => i.ExampleRoles.Name)" to achieve the same thing.
Upvotes: 2