Search icon
Subscription
0
Cart icon
Close icon
You have no products in your basket yet
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Entity Framework Core Cookbook - Second Edition

You're reading from  Entity Framework Core Cookbook - Second Edition

Product type Book
Published in Nov 2016
Publisher Packt
ISBN-13 9781785883309
Pages 324 pages
Edition 2nd Edition
Languages
Author (1):
Ricardo Peres Ricardo Peres
Profile icon Ricardo Peres

Table of Contents (15) Chapters

Entity Framework Core Cookbook - Second Edition
Credits
About the Author
About the Reviewer
www.PacktPub.com
Preface
1. Improving Entity Framework in the Real World 2. Mapping Entities 3. Validation and Changes 4. Transactions and Concurrency Control 5. Querying 6. Advanced Scenarios 7. Performance and Scalability Pitfalls Index

Implementing the repository pattern


This recipe is an implementation of the Repository Pattern, which allows us to abstract the underlying data source and the queries used to obtain the data.

Getting ready

We will be using the NuGet Package Manager to install the Entity Framework Core 1 package, Microsoft.EntityFrameworkCore. We will also be using a SQL Server database for storing the data, so we will also need Microsoft.EntityFrameworkCore.SqlServer.

To mock interfaces and base classes, we will use Moq.

Finally, xunit is the package we will be using for the unit tests and dotnet-text-xunit adds tooling support for Visual Studio. Note that the UnitTests project is a .NET Core App 1.0 (netcoreapp1.0), that Microsoft.EntityFrameworkCore.Design is configured as a build dependency, and Microsoft.EntityFrameworkCore.Tools is set as a tool.

Open Using EF Core Solution from the included source code examples.

Execute the database setup script from the code samples included for this recipe. This can be found in the DataAccess project within the Database folder.

How to do it…

  1. Create a new file in the DataAccess project, with this content:

    using System.Linq;
    namespace DataAccess
    {
        public interface IRepository<out T> where T : class
        {
            IQueryable<T> Set<T>() where T : class;
            void RollbackChanges();
            void SaveChanges();
        }
    }
  2. In the DataAccess project, add a new C# interface named IBlogRepository with the following code:

    using System.Linq;
    namespace DataAccess
    {
        public interface IBlogRepository : IRepository<Blog>
        {
        }
    }
  3. In the DataAccess project, create a new C# class named BlogRepository containing the following code:

    using System.Data.Entity;
    using System.Linq;
    using BusinessLogic;
    namespace DataAccess
    {
        public class BlogRepository : IBlogRepository
        {
            private readonly IDbContext _context;
            public BlogRepository(IDbContext context)
            {
                _context = context;
            }
            public IQueryable<Blog> Set()
            {
                return _context.Set<Blog>();
            }
        }
    }
  4. We'll add a new unit test in the UnitTests project that defines a test for using the repository with the following code:

    using System.Linq;
    using BusinessLogic;
    using DataAccess;
    using Moq;
    using Xunit;
    namespace UnitTests
    {
        public class RepositoryTest : BaseTest
        {
            [Fact]
            public void ShouldAllowGettingASetOfObjectsGenerically()
            {
                //Arrange
                var data = new[] { new Blog { Id = 1, Title = "Title" },              newBlog { Id = 2, Title = "No Title" } }.AsQueryable();
                var mock = new Mock<IDbContext>();
                mock.Setup(x => x.Set<Blog>()).Returns(data);
                var context = mock.Object;
                var repository = new BlogRepository(context);
                //Act
                var blogs = repository.Set();
                //Assert
                Assert.Equal(data, blogs);
            }
        }
    }
  5. In the BlogController class of the UI project, update the usage of BlogContext so it uses IBlogRepository with the following code:

    using BusinessLogic;
    using DataAccess;
    using System.Linq;
    using Microsoft.AspNet.Mvc;
    namespace UI.Controllers
    {
        public class BlogController : Controller
        {
            private readonly IBlogRepository _repository;
            public BlogController(IBlogRepository repository)
            {
                _repository = repository;
            }
            public IActionResult Index()
            {
                var blog = _repository.Set().First();
                return View(blog);
            }
        }
    }
  6. Finally, we need to register the IBlogRepository service for dependency injection so that it can be passed automatically to the HomeController's constructor. We do that in the Startup.cs file in the UI project, in the ConfigureServices method:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
        services.AddSingleton<IConfiguration>(_ => Configuration);
        services.AddScoped<IDbContext>(_ => new BlogContext(Configuration["Data:Blog:ConnectionString"]));
        services.AddScoped<IBlogRepository>(_ => new BlogRepository(_.GetService<IDbContext>()));
    }

How it works…

We start off with a test that defines what we hope to accomplish. We use mocking (or verifiable fake objects) to ensure that we get the behavior that we expect. The test states that any BlogRepository function will communicate with the context to connect for the data. This is what we are hoping to accomplish, as doing so allows us to layer tests and extension points into the domain.

The usage of the repository interface is a key part of this flexible implementation as it will allow us to leverage mocks, and test the business layer, while still maintaining an extensible solution. The interface to the context is a straightforward API for all database communication. In this example, we only need to read data from the database, so the interface is very simple.

Even in this simple implementation of the interface, we see that there are opportunities to increase reusability. We could have created a method or property that returned the list of blogs, but then we would have had to modify the context and interface for every new entity. Instead, we set up the Set method to take a generic type, which allows us to add entities to the usage of the interface without modifying the interface. We will only need to modify the implementation.

Notice that we constrained the IRepository interface to accept only the reference types for T, using the where T : class constraint. We did this because value types cannot be stored using Entity Framework; if you had a base class, you could use it here to constrain the usage of the generic even further. Importantly, not all reference types are valid for T, but the constraint is as close as we can get using C#. Interfaces are not valid because Entity Framework cannot construct them when it needs to create an entity. Instead, it will produce a runtime exception, as they are valid reference types and therefore the compiler won't complain.

Once we have the context, we need to wrap it with an abstraction. IBlogRepository will allow us to query the data without allowing direct control over the database connection. We can hide the details of the specific implementation, the actual context object, while surfacing a simplified API for gathering data. We can also introduce specific operations for the Blog entity here.

The other interface that we abstracted is the IDbContext interface. This abstraction allows us to intercept operations just before they are sent to the database. This makes the untestable part of the application as thin as possible. We can, and will, test right up to the point of database connection.

We had to register the two interfaces, IDbContext and IBlogRepository, in the ASP.NET dependency resolver. This is achieved at startup time, so that any code that requires these services can use them. You will notice that the registration for IBlogRepository makes use of the IDbContext registration. This is OK, because it is a requirement for the actual implementation of BlogRepository to rely on IDbContext to actually retrieve the data.

There's more…

Keeping the repository implementation clean requires us to leverage some principles and patterns that are at the core of object-oriented programming, but not specific to using Entity Framework. These principles will not only help us to write clean implementations of Entity Framework, but can also be leveraged by other areas of our code.

Dependency Inversion Principle

Dependency inversion is another SOLID principle. This states that all of the dependencies of an object should be clearly visible and passed in, or injected, to create the object. The benefit of this is twofold: the first is exposing all of the dependencies so the effects of using a piece of code are clear to those who will use the class. The second benefit is that by injecting these dependencies at construction, they allow us to unit test by passing in mocks of the dependent objects. Granular unit tests require the ability to abstract dependencies, so we can ensure only one object is under test.

Repository and caching

This repository pattern gives us the perfect area for implementing a complex or global caching mechanism. If we want to persist a value into the cache at the point of retrieval, and not retrieve it again, the repository class is the perfect location for such logic. This layer of abstraction allows us to move beyond simple implementations and start thinking about solving business problems quickly, and later extend to handle more complex scenarios as they are warranted by the requirements of the specific project. You can think of repository as a well-tested 80%+ solution. Put off anything more until the last responsible moment.

Mocking

The usage of mocks is commonplace in tests because mocks allow us to verify underlying behavior without having more than one object under test. This is a fundamental piece of the puzzle for test-driven development. When you test at a unit level, you want to make sure that the level directly following the one you are testing was called correctly while not actually executing the specific implementation. This is what mocking buys us.

Where generic constraint

There are times when we need to create complex sets of queries that will be used frequently, but only by one or two objects. When this situation occurs, we want to reuse that code without needing to duplicate it for each object. This is where the where constraint helps us. It allows us to limit generically defined behavior to an object or set of objects that share a common interface or base class. The extension possibilities are nearly limitless.

See also

In this chapter:

  • Implementing the unit of work pattern

  • Creating mock database connections

You have been reading a chapter from
Entity Framework Core Cookbook - Second Edition
Published in: Nov 2016 Publisher: Packt ISBN-13: 9781785883309
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime}