Creating new objects in Entity Framework using DbSet<T>.Create() - c#

I am migrating a project from Linq-to-SQL to Entity Framework with POCO's, and I'm not sure how should I be creating new objects now in EF.
On the surface DbSet<T>.Create(), which creates a dynamic proxy, looks like the better way because it helps me with two-way binding automatically (If I build my POCO's correctly), but from what I saw while browsing open source projects, most just use the standard ctor new T().
The only con I can think of in using DbSet<T>.Create() is that it makes my code somewhat coupled to EF.
Is there anything else that I am missing?
Which way will help me in creating a testable, robust software more easily?

You probably need to think about abstracting the EF code away from the rest of your non-EF code, so you can replace it as needed in order to do your testing.
One of the ways (and the way I do it) is to use a generic repository:
public interface IGenericRepository<TContext, TEntity>
where TEntity : class, IEntity
where TContext : IDbContext
{
TEntity NewEntity();
}
public class GenericRepository<TContext, TEntity> : IGenericRepository<TContext, TEntity>
where TEntity : class, IEntity
where TContext : IDbContext
{
private readonly IDbContext _context;
public GenericRepository(IUnitOfWork<TContext> uow)
{
_context = uow.Context;
}
public TEntity NewEntity()
{
var t = _context.Set<TEntity>().Create();
_context.Set<TEntity>().Add(t);
return t;
}
}
Note that I have only included the code which directly covers your question - creating a new entity from the DBSet but also hiding the underlying method so you can easily reimplement it in a non-EF fashion.
You may get a few replies or comments about the use of generic repositories, how they are bad etc - its all opinions rather than facts, investigate the various arguments for and against and come to your own conclusions rather than be brown beaten by other people. I use them to hide the underlying persistence layer (EF, ADO.Net etc), making it easy to push a testing implementation to code further up in the chain if I need to.

Related

Where should I put the complex queries using the Repository Pattern?

I have an application in which I use Entity Framework, and I have a class called BaseRepository<T> with a few basic CRUD methods, such as (Get, GetAll, Update, Delete, Insert), and from this class I generate my specific repositories, such like BaseRepository <Products>, BaseRepository<People>, BaseRepository<Countries> and many more.
The problem is that, when I have a complex logic in the service, that involves making joins of several tables and that does not return an entity, but an object that is handled in the service (it is neither a DB entity nor a DTO), I find that repositories don't help me much with just basic CRUD operations.
Where should I put this query complex? in which of the repositories should it be? How do I join these repositories? The problem is that I see that the repositories handle a single entity, what should I do in this case? I've been doing some research and read that returning IQueryable<T> is bad practice, so I rule out that possibility of sending IQueryable<T> of the tables I'm going to join the service and do it there.
I've researched and found no clear answer. I would like to know how and where these complex queries are organized, since I also want to respect the responsibility of each repository with its respective entity.
I would like to know how and where these complex queries are organized, since I also want to respect the responsibility of each repository with its respective entity.
The complex queries are the responsibility of the code that is requesting the data, not the responsibility of the repository. The single responsibility of the repository is to provide access to the data, not to provide every possible request shape that may be needed in any use case. You really want to write methods in your repositories like:
customerRepo.GetCustomerWithLastTenOrdersAndSupportCasesAsDTO()
or
customerRepo.GetCustomerForCustomerSupportHomePage()
Of course not. So your repository provides a property of type IQueryable<T> or DbSet<T> which can be used as a starting point for consumers to add whatever queries they need.
I've been doing some research and read that returning IQueryable is bad practice
Don't beleive everything you read. There's really not a good alternative to exposing IQueryable<T> from your repository. And once you digest that, there's not much of a reason to have any repository type other than your DbContext subtype.
Its hard to answer without having a code to understand what you want to achieve, hopefully my answer gives you an idea on how you can use abstract classes to override your Queryable Collection. If your requirement is more complex, can you provide more information with example code.
Create your BaseRepository like this -
public abstract class BaseRepository<T>
{
public IQueryable<T> Collection { get; set; }
public readonly DbContext _context;
public BaseRepository(DbContext context)
{
_context = context;
Collection = SetQueryableCollection();
}
public virtual IQueryable<T> SetQueryableCollection() => _context.Set<T>();
// CRUD Operations here for e.g. -
public virtual async Task<List<T>> Get()
{
return await Collection.ToListAsync();
}
}
Now, the class that inherits this -
public class ProductRepository : BaseRepository<Product>
{
public ProductRepository(MyContext context) : base(context)
{
}
//now override the method that sets the collection
public override IQueryable<Product> SetQueryableCollection() =>
_context.Set<Product>().Include(p => p.Brand).ThenInclude(...);
// things to keep in mind, the _context is public in the way I've done it. You can change that and directly expose the Collection and set it to your need per entity type.
}
So now your GET method uses the overriden method to set the Collection.

what's a good way to handle generic db conn logic in dal/repo layer?

I'm developing a repo layer with several different repos like UserRepository, ReportRepository, etc. The connection string will be injected through the constructor of the repo. This pattern will be implemented consistently for all repos. Is there a way I can implement this logic generically without having to repeat this implementation for each repo? Each repo currently implements a corresponding interface. For example, UserRepository : IUserRepository. Is there a pattern you normally use to avoid the duplicate code? I could use abstract classes but I'm wondering if that would be too heavy. I've always seen repo classes implementing interfaces in past solutions I've worked on
Just use a base class, the typical pattern is:
public class UserRepository : IUserRepository,
RepositoryBase
{
public UserRepository(string connectionString)
: base(connectionString)
{
}
}
and put common code in RespositoryBase.

Ninject and DbContext

Building a app with EF 6 and Ninject 3.2.2 I'm having some trouble wrapping my head around how to access the DbContext in a intelligent way.
As I understand in the newer versions of Ninject only constructor injection is encouraged. As EF 6, itself is repo and unit of work I'm not doing any abstractions on top of EF.
If would like to be able to use multiple small units of works so injecting the DbContext (uow) into every class that needs it is not going to work.
In a non IoC way I would do like this:
Using(var db = new DbContext){}
How do achieve this using Ninject as I no longer can do kernel.get in my using block...
I'd consider two approaches:
Create general DbContext, which can be hidden behind an interface:
public interface IPortalContext : IDisposable
{
DbSet<User> Users { get; }
DbContext Context { get; }
}
public class PortalContext : DbContext, IPortalContext
{
public PortalContext()
: base("PortalConnectionString")
{
}
public virtual DbSet<User> Users { get; set; }
}
then you can inject your context to the constructor without problem.
Create many small contexts which can be used in different scenarios and classes.
I don't think that first approach is bad since it only encapsulates your DbSets and DbContext making it easier to inject and test. You don't make any unnecessary layers above EF and whole interface seems quite transparent.
Anyway this approach is better than making whole IRepository<T> stuff to access another repository...
I'm not sure what you mean by "multiple small unit of works", but just for exposure, this is what I've done in a recent application:
Divided the domain in small bounded contexts (this is more of a conceptual step)
Each bounded context has: a context, a repository, a repository factory
Each context implements an IContext and a BaseContext that gives basic methods and common properties (IContext will be useful for mocking)
Each repository takes the relative context as a constructor paramenter
This is an example of a repository factory
public class CartRepositoryFactory : IRepositoryFactory
{
public IRepository Generate(CartContext ctx)
{
return new CartRepository(ctx);
}
}
At the application service layer, I inject a UoW and the repository factory that I need
If I want to work with several different context in one service, I simply create another service and combine the services that I need, injecting them
You might be asking, but why?!? This is madness!!
Well, because if the Repository manages the DbContext, then I can only do one operation per class instantiation. This allows me to open a DbContext and make several calls to the Repository.
Of course now you have the same problem at application service level, you can only call one method per instantiation, but it's far easier to manage.
Ultimately it all comes down to your taste: would you rather have a thin service or a thin repository?

Applying Repository Pattern to ReportViewModels

public interface IRepository<TEntity>
{
TEntity FindById(Guid id);
void Add(TEntity entity);
void Remove(TEntity entity);
}
This is a simple generic repository. If I have a Product entity, this repository can insert, update, and delete (using Entity Framework).
But I have report based types that I created.
For example:
Products that grouped by salesmen.
Number of orders sent by each shipper.
public class OrdersWithShipper {
public string ShipperName{get;set;}
public string NumberOfOrder{get;set;}
}
And so on.
So I should create complex queries to many tables that related. But query result object is not representing with repository TEntity entity type.
I have many report type like this. How can I solve this problem?
The direct problem of this question is:
So I should create complex queries to many tables that related. But
query result object is not representing with repository TEntity entity
type.
I would say you should not be using the repository pattern here as it breaks it. E.g a repository should be dealing with returning and managing the domain object it is designed for, in order to support domain behavior, not random query objects to support reporting behavior.
By not sticking to the same type you will almost certainly end up not knowing where to draw the line, e.g what query object goes with what repository etc... So you should just keep it simple.
Apply a different pattern to reporting (or querying) for example. Maybe create classes for your view models (View Model Builders?) that are directly dependent on IDbSet<T> for their querying logic.
Or, abstract further and have a query handler / query provider pattern (this would be my choice).
Look at the answer here:
Well designed query commands and/or specifications
I have used similar pattern to this with great success.
My technique in doing this is to wrap the Repository in a Service class that can accept the ViewModels. In other words, my Controllers are using the Service classes that I make and not the repositories directly.
Also, I use the AutoMapper library to map
Example below:
public class OrderWithShipperProductService()
{
public ProductRepository { get; set; }
public OrderWithShipperProductService(ProductRepository repo)
{
this.ProductRepository = repo;
}
public void AddOrderWithShipperProduct(OrderWithShipperProduct model)
{
var entity = Mapper.Map<TEntity>(model);
ProductRepository.Add(entity);
}
}
You may need to learn Automapper here.
But you may also map it yourself in the constructor if you want.
Or you may also create your own mapping functions.

How to dispose object context in repository pattern

I implemented a repository pattern to my application dat .
I have :
public class EFRepository<T>
{
DbContext // My db context
public IQureable<T> GetQuery()
{
DataContext.CreateQuery(...);
}
}
Now let say I have user repository :
public class UserRepository : EFRepository
{
public UserGetUserDetails(int userId)
{
GetQuery().Where(u=>u.Id = userId).First();
}
}
my problem is how to release the DbContext when I use the EF repository in derived repositories.
Lets say : UserRepository: EFRepository , and it uses the GetQuery then I have to dispose the context.
Any good idea how to make this in generic repository?
You should think about what unit of work you have. (there are many other tutorials on the internet). The idea is to keep the same dbcontext and to re-use it while being in the same unit of work. This way, entities will already be attached to the context when needing them, etc..
Now, this being a web application, your unit of work would be in this case a request. While in the same request, reuse your DBContext. There are many ways to do this and just off the top of my head - you will want something like 'OnActionExecuting' where you take care of your context.
But even better would be to use an Inversion of Control pattern (there are many frameworks out there that use this, i primarily use NInject . This will automatically create a new instance of a certain class, when needed, depending on the scope you suggested - in this case 'onRequestScope'. A lot more to say about IoC but not the scope of the question
I have used a similar pattern in the past and in my case I actually inherited from DbContext, which itself implements IDisposable. Provided you are using EFRepository or classes derived from it in a using block you should be fine.
If you would prefer a DbContext member variable, then EFRepository will need to implement IDisposable and call DbContext.Dispose() from its Dispose method.

Categories