I am working on a .Net core project and I have 5 look up tables, so instead of making repository and service for each one I want to make generic repository and generic service for them.
My problem is in implementing FindByID using expressions. I understand the idea behind it but I don't know where or how to use. Any help would be appreciated
Generic Repository Function
private readonly NexusContext _context;
IMapper _mapper;
public GenericRepository(NexusContext context)
{
_context = context;
}
public GenericLookupDTO GetById(Expression<Func<T, bool>> predicate)
{
var obj = _context.Set<T>().Where(predicate);
var objMapped = AutoMapping.mapper.Map<GenericLookupDTO>(obj);
return objMapped;
}
Service Function
private readonly IGenericRepository<T> _genericRepository;
private readonly IUnitOfWork _unitOfWork;
public ConfigurationService(IGenericRepository<T> genericRepository, IUnitOfWork unitOfWork)
{
this._genericRepository = genericRepository;
this._unitOfWork = unitOfWork;
}
List<Errors> errors = new List<Errors>();
try
{
var obj = _genericRepository.GetById(predicate);
if (obj == null)
{
errors.Add(new Errors("404", "Couldn't find configration"));
return new GenericResponse<GenericLookupDTO>(errors, new GenericLookupDTO());
}
await _unitOfWork.CompleteAsync();
return new GenericResponse<GenericLookupDTO>("1", "Success", obj);
}
catch (Exception ex)
{
errors.Add(new Errors(ex.HResult.ToString(), ex.InnerException.Message));
return new GenericResponse<GenericLookupDTO>(errors, new GenericLookupDTO());
}
Controller function
private readonly IConfigurationService<LutNationality> _configurationService;
public NationalityController(IConfigurationService<LutNationality> configurationService)
{
this._configurationService = configurationService;
}
[HttpGet("Id")]
[ProducesResponseType(typeof(GenericLookupDTO), (int)HttpStatusCode.OK)]
public async Task<IActionResult> GetByIdAsync()
{
var result = await _configurationService.GetByIdAsync(//what should i pass here);
if (result.operationSuccess)
return Ok(result);
return BadRequest(result);
}
First look up Table
public partial class LutGender
{
public int Id { get; set; }
public string Value { get; set; }
}
Second look up Table
public partial class LutNationality
{
public int Id { get; set; }
public string Value { get; set; }
}
Generic DTO
public class GenericLookupDTO
{
public int Id { get; set; }
public string value { get; set; }
}
The repository pattern is already implemented by the DbSet<T> and consists in few operations over your entity to store and retrive him from an abstracted data store. Just your entity, it's very important on DDD.
But, I know that sometimes we need to put another layer of abstraction over this, to deal with another databases like nosql, for example.
In this case, usually we create a gereneric repository, and it's needed to supply a way to make operations based on what type this repository is. To accomplish this, we need to define a common interface for our entities with an Id and implement this on those entities:
public interface IEntity
{
Guid Id (get; set;}
}
That way, constraining your generic repository to this type of interface provides you ability to access the Id on the methods.
public class GenericRepository<T> : IGenericRepository<T> where T : IEntity
{
private readonly NexusContext _context;
IMapper _mapper;
public GenericRepository(NexusContext context)
{
_context = context;
}
public GenericLookupDTO GetById(Guid id)
{
var obj = _context.Set<T>().FirstOrDefault(x => x.Id = id);
var objMapped = AutoMapping.mapper.Map<GenericLookupDTO>(obj);
return objMapped;
}
}
I really recomend you to don't return DTOs from repository, if you need to aggregate data from many different entities that are not related, use a different layer of data access, very simplified, and create freely your own queries, using dapper or even EF but projecting directly DTOs.
If the DTO is identical of an entity, in this case use the repository to retrieve the entity and on application layer map this entity to a DTO.
When you have time, take a look at DDD principles to clarify a little bit more those subjects.
Back to your example, on the controller you will need to inject the right type of generic repository, like:
IGenericRepository<Customer> customerRepository
and configure your dependecy injection container to resolve generic types, like:
services.AddTransient<IGenericRepository<>, GenericRepository<>>();
The service will rely just on IGenericRepository<T> as you did.
But, if you want to query freely your entities, I recommend you make use of OData or GraphQl, that will provides you more control over queries.
I'm tried to be very simplistic here, so, I hope that i could clarify things a little bit more for you!
Related
The scenario:
I have a couple websites that I'm rebuilding with Blazor, all do e-commerce. What I want to do is extract the accounting logic (i.e. Orders, OrderItems, Accounts, Transactions, etc) and data operations into an
"Accounting" DLL so I don't have to repeat the code.
I've got the above Entities defined in the DLL, then in the WebApp.Server's DbContext I have the appropriate DbSets.
In the "Accounting" DLL, I have an interface:
public interface IDbAccountringService
{
DbSet<Account> Accounts { get; set; }
//etc
}
which the DbContext in WebApp.Server implements:
public class Db : ApiAuthorizationDbContext<User>, IDbAccountringService
{
public Db(
DbContextOptions options,
IOptions<OperationalStoreOptions> operationalStoreOptions) : base(options, operationalStoreOptions)
{
}
public DbSet<Account> Accounts { get; set; }
}
Then in the "Accounting" DLL, I have the following generic class:
public class DbAccountingService<T> where T : DbContext, IDbAccountringService
{
DbContext dbContext { get; set; }
public DbAccountingService(DbContext T)
{
dbContext = T;
}
public Account[] GetAccounts()
{
//The compiler doesn't see Accounts
return dbContext.Accounts.ToArray();
//It also doesn't see Accounts on itself
return this.Accounts.ToArray();
// However, it does see all the DbContext methods
dbContext.SaveChanges();
}
}
which I instantiate and use in my controller:
[Route("accounting/accounts")]
[ApiController]
public class JournalController : BaseApiController
{
DbAccountingService<Db> _dbAccountingService;
public JournalController(Db db, MtGlobals mtGlobals) : base(mtGlobals)
{
_dbAccountingService = new DbAccountingService<Db>(db);
}
[HttpGet("get-accounts")]
public Account[] GetAccounts()
{
return _dbAccountingService.GetAccounts();
}
}
As the comments in DbAccountingService<T> indicate, the compiler recognizes that dbContext is in fact a DbContext, but it doesn't recognize that it also implements IDbAccountringService.
I'm a little fuzzy on generics, though I usually get them working, however, here, no luck.
Is what I'm trying to do possible? I want to extract all the data operations into the "Accounting" DLL so that I don't have to write duplicate code for each website.
Your dbContext field is of type DbContext:
DbContext dbContext { get; set; }
public DbAccountingService(DbContext T)
{
dbContext = T;
}
Be aware, that you constructor parameter is of type DbContext too with parameter name T. So this T has nothing to do with the generic type parameter, it's just a parameter name.
You want the dbContext property to be the generic type:
T dbContext { get; set; }
public DbAccountingService(T context)
{
dbContext = context;
}
The relevant par is, that your field has type T (because your where constraints this to implement interface IAccountingService.
I'm running into an InvalidOperationException because "An entity object cannot be referenced by multiple instances of IEntityChangeTracker." on the first line of EntityFrameWorkRepository.Create().
I know this is due to having multiple database contexts, but in this case I'm a bit lost as the code has no obvious second context since all database access goes through a designated object whose sole purpose is managing database contexts. This was done as the web application in question is fairly interactive and so the user is constantly creating new objects which must be saved in the database. This was causing issues with the previous design, which used locking and a single context, thus the code was refactored and works, except for the method in question.
EF class:
public class EntityFrameWorkRepository<TKey, TEntity> : IDisposable, IRepository<TKey,TEntity> where TEntity: class
{
private readonly IDbContext _context;
private IDbSet<TEntity> _entities;
public EntityFrameWorkRepository()
{
_context = new ApplicationDbContext();
}
private IDbSet<TEntity> Entities
{
get { return _entities ?? (_entities = _context.Set<TEntity>()); }
}
public void Create(TEntity entity)
{
Entities.Add(entity);
_context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
}
The service object used for all DB access:
public class Service : IService
{
public const string Persistance = "Persist";
public const int CacheTaskSeconds = 300; //Check every 5 minutes
public const double IdleMinutes = 30.0;
private readonly IKvpRepository<int, SimulationCollection> _simulationCollectionAppStateRepository;
private readonly UserManager<ApplicationUser> _userManager;
public Service(IKvpRepository<int, SimulationCollection> simulationCollectionAppStateRepository)
{
_userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
AddTaskToCache(Persistance, CacheTaskSeconds);
}
public SimulationCollection CreateCollection(Guid userId, string name, string description)
{
using (var _simulationCollectionEFRepository = new EntityFrameWorkRepository<int, SimulationCollectionEntity>())
{
var applicationUser = _userManager.FindById(userId.ToString());
if (applicationUser == null)
throw new ArgumentOutOfRangeException("ApplicationUser matching userId doesn't exist");
var collectionEntity = new SimulationCollectionEntity(applicationUser, name, description);
_simulationCollectionEFRepository.Create(collectionEntity);
return collection;
}
}
}
The object I'm trying to add to the database:
public class SimulationCollectionEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public virtual int Id { get; set; }
public string Name { get; set; }
public virtual ApplicationUser User { get; set; }
public DateTime DateCreated { get; set; }
public string Description { get; set; }
[ForeignKey("SimulationCollectionEntityId")]
public virtual ICollection<SimulationEntity> Simulations { get; set; }
[Obsolete("Only needed for serialization and materialization", true)]
public SimulationCollectionEntity() {}
public SimulationCollectionEntity(ApplicationUser currentUser, string name, string description)
{
User = currentUser;
Name = name;
Description = description;
DateCreated = DateTime.Now;
}
}
Is there an easy way to view what contexts a given object might be attached to? I already checked to see if collectionEntity is attached to _userManager since it has a dbContext, but its state is detached. Does EF maybe expect me to add objects in a different way than I am? I suspect that the attributes in SimulationCollectionEntity might be causing me trouble but I'm new to Entity Framework and I'm not sure. Should I maybe be going for a different design instead like this?
You might want to consider a unit of work like approach where one context is shared among multiple repositories. The accepted answer for this post is a good example. I have seen ContextPerRequest solutions like the one in your example, but I've never been crazy about them. Ideally you want a short lived context that does one thing like add an invoice and two invoice items - a single unit of work. You could then wrap the whole operation in a TransactionScope and have it succeed or fail as a unit.
I am working on an application where my database schema does not match up well to my domain model, and modifications to the database schema are not under my control. Because of this, I end up doing a lot of mapping in my repository calls, and I have many concrete repos to handle the mapping to and from the database (using entity framework database-first). What I am looking for is an elegant way to make calls to my repositories based on the domain entity object type. Thus far, the domain model itself is still very anemic, as we are still in the process of defining business rules.
I have seen an example elsewhere (can't recall the link) where the repository calls were passed through the domain entities via a static property, but I do not know if this will present threading issues or whether it violates any domain model principles, especially if we decide to implement DI/IoC down the road.
Here is an example of what I have so far. For the sake of brevity, I have simplified the mapping calls to the database, as the mapping in the actual application is more complex.
Repository example:
public interface IRepository<T>
{
T GetById(int id);
void Save(T entity);
}
public abstract class RepositoryFactory<T> : IRepository<T>
{
protected MyDbContext db;
protected int userId;
protected RepositoryFactory()
{
this.db = new MyDbContext();
this.userId = WebSecurity.GetCurrentUser().UserId;
}
public abstract T GetById(int id);
public abstract void Save(T entity);
}
public class CustomerRepository : RepositoryFactory<Customer>
{
public override void Save(Customer customer)
{
var entity = db.customers.FirstOrDefault(p => p.customerid == customer.Id && p.users.userid == userId);
if (entity == null) return; // TODO: Add error trapping
// Mapping (lots of reshaping happening here)
entity.customername = customer.Name;
entity.customeraddress = customer.Address;
// ...
// Save changes to DB
db.Entry(entity).State = EntityState.Modified;
db.SaveChanges();
}
public override Customer GetById(int id)
{
var entity = db.customers.FirstOrDefault(p => p.customerid == id && p.users.userid == userId);
if (entity == null) return null; // TODO: Add error trapping
return new Customer
{
Name = entity.customername,
Address = entity.customeraddress,
// ...
};
}
}
Domain Entity example:
public class Entity { public int Id { get; set; } }
public class Customer : Entity
{
public string Name { get; set; }
public string Address { get; set; }
// Does this violate any domain principles?
public static IRepository<Customer> Repository
{
get { return new CustomerRepository(); }
}
}
With this code, from my controller I can do something like:
Customer customer = Customer.Repository.GetById(id);
Instead of:
IRepository<Customer> repo = new CustomerRepository();
Customer customer = repo.GetById(id);
This seems like a very elegant solution to my problem, and it also keeps me from needing to include the Repository namespace in my controllers (MVC). If this smells funny and there is a better way to handle this, I'd love to learn. The only other thing I can think of is creating a separate crud service to handle my repository calls, but I imagine for that I would need a dictionary or hash table to map my concrete repos to my domain model objects, and that seems like it would be a maintenance nightmare.
I'd suggest using an inversion of control (dependency injection) container and injecting your repositories into your controllers or wherever. This way you can use them like this:
public class HomeController : Controller
{
private readonly IRepository<Customer> _customerRepository;
public HomeController(IRepository<Customer> customerRepository)
{
_customerRepository = customerRepository;
}
public ActionResult Index(int id)
{
var customer = _customerRepository.GetById(id)
return View(customer);
}
}
This way, if you ever need to replace CustomerRepository class, or need to have multiple versions (say CustomerRepositoryEntityFramework or CustomerRepositoryNHibernate) you can simply replace a new class inheriting from IRepository and your controller code will still continue to work with no change.
I recommend using Castle Windsor, or Ninject, or one of the many other IoC containers.
Also, you generally want to keep your domain entities as poco's (Plain Old CLR Object). This means separating everything out of your entities including validation, business rules, etc. and simply having only its properties. This allows you to pass your domain entities through the pipeline more easily, specially since you are in the early stages of development. This will offer you the most flexibility in the future.
I have a nice clean domain layer in my app that was developed in a DDD fashion. The database was not considered at all when developing the domain. Property names make sense, aren't in ALL CAPS, and are relevant to my application.
Today, I am implementing a repository to pull from an existing EF DbContext. The DbContext was developed to (basically) match a poorly-designed Oracle database.
Ideally, I would like to implement a repository like this:
public interface IRepository {
IQueryable<T> Find<T>(Expression<Func<T, bool>> query) where T : IMyDomainEntity;
}
T is my domain entity. But, inside my Find method in my repository, I have to...
Somehow convert the expression to work with the DbContext
I am not sure how to do this yet.
Query the DbContext
Once the expression is 'mapped', this is simple
Somehow map to my domain object
I'm sure I can use AutoMapper or implement my own mapper.
Return an IQueryable having not made a trip to the database yet.
Not sure this is possible after all the meddling done in #'s 1 - 3
So, how has this problem been solved in the past? Are there any reusable patterns here?
Well, you're on the right track already, just implement what your say you want :)
1.You're passing an expression into your find method so, just use that expression in your Where clause
2.You just need to get the correct DbSet from your DbContext to query against, DbContext has a method to get the DbContext of a given type, use that and you can query like
public IQueryable<T> Find<T>(Expression<Func<T, bool>> query) where T : IMyDomainEntity
{
var dbSet = context.Set<T>();
return dbSet.Where(query);
}
3.If your domain objects are not the ones mapped by EF to the database, you'll need to customize your mapping against what's in your DB in your DbContext class (no need for automapper for that), so you would have something like this in your DbContext class
public class MyContext : DbContext
{
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.Map(a => a.ToTable("DB_USERS"))
.Property(a => a.Email).HasColumnName("MAIL");
base.OnModelCreating(modelBuilder);
}
}
To map from the table DB_USERS in the DB to the class User, having different names for the fields, etc. here's an article on that
http://www.codeproject.com/Articles/165720/Using-the-Code-First-Model-Configuration-Classes
You could also map the properties to the correct table columns using attributes if you don't want/can't change your DbContext class
http://msdn.microsoft.com/en-us/data/gg193958
Or you can have a different set of entities that are mapped to your DB and use automapper to translate them into your domain objects, but you lose no. 4 bellos since you'll need to materialize the query to automap it to your domain model.
4.No need to do anything special, EF takes care of the that
UPDATE: Solution without having access to the DbContext (not fully generic version but works)
The idea is to create the mapping part of the repository for each domain class, so all gets binded correctly. Continueing with the User domain model and DBUser table model:
public class User : IDomainModelEntity
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
public class DBUser
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int USER_ID { get; set; }
[Required]
[MaxLength(150)]
public string USER_NAME { get; set; }
[Required]
[MaxLength(260)]
public string USER_MAIL { get; set; }
}
Then you would have an abstract Repository and an a concrete repository per domain class that implements the basic GetAll query mapped:
public abstract class Repository<T> where T : IDomainModelEntity
{
protected readonly DbContext _context;
public Repository(DbContext context)
{
_context = context;
}
public abstract IQueryable<T> GetAll();
public IQueryable<T> Find(Expression<Func<T, bool>> predicate)
{
return GetAll().Where(predicate);
}
}
public class UserRepository : Repository<User>
{
public UserRepository(DbContext context)
: base(context)
{
}
public override IQueryable<User> GetAll()
{
return _context.Set<DBUser>()
.Select(u => new User
{
Id = u.USER_ID,
Name = u.USER_NAME,
Email = u.USER_MAIL
});
}
}
now to use it you will just call the find or get all on the repository...
using (var context = new CompanyDbContext())
{
var repo = new UserRepository(context);
var list = repo.Find(a=>a.Id >= 2).ToList();
list.ForEach(a => Console.WriteLine("Id: {0}, Name {1}, email {2}", a.Id, a.Name, a.Email));
}
It is not fully generic since you will need to pass a repository for each domain class you need to use, but it may be an acceptable compromise
Hope this helps
Let just say I have the following data models:
public class Account
{
public string Username { get; set; }
public string Password { get; set; }
}
public class Configuration
{
public string Key { get; set; }
public string Value { get; set; }
}
For now, each of them has their own repository for data access, and uses entity framework as its unit of work/DbContext. I'm planning to pull out the Configuration part out of the entity frame and use Redis or Memcached as its data access. I might even to switch the EF to NHibernate or no ORM at all, and I might switch the database to MongoDB or CouchDB.
What is the good way to do this? To be ignorant of all those lower layer stuff in my business logic? What kind of pattern to use? Is it possible or is it just bad things to design for changes like this?
Thanks :)
As stated in the previous post, you should go the "way of the Interface".
I personally do not implement directly the repository for each orm but I use a little variation.
Using your example...
public interface IAccountRepository
{
Account Get(int id);
void Delete(int id);
...other method...
}
then you create your repository
public class AccountRepository : IAccountRepository
{
private readonly IUnitofWork unitofWork;
public AccountRepository(IUnitofWork unitofWork)
{
this.unitofWork = unitofWork;
}
//Implement interface method
public Account Get(int id)
{
//some logic or just the call to the unit of work
return unitofWork.Get(id);
}
}
I am happy with this solution because I end up with only one repository that 90% of the time use linq to query so I don't have to write the sql for each unit of work and every time I have to write a "GetAllProducts" with paging I do not have to write the same code (and tests) for every unit of work, but only for my repository. This is a simple example obviously so I hope you get the idea.
You can make a RepositoryBase that implement a method Find() or Query() which use linq.
Then with your Castle Windsor or ninject or whatever you can inject the unit of work you prefer. Hope it helps.
Update:
a sample of my UnitofWorkBase that implement nhibernate is something similar:
public class NHUnitofWork<T> : IUnitofWork<T> where T : EntityBase
{
protected INHSessionBuilder SessionBuilder { get; private set; }
public NHPersistorBase(INHSessionBuilder sessionBuilder)
{
SessionBuilder = sessionBuilder;
}
public T Get(int id)
{
T result = null;
ISession session = SessionBuilder.GetSession();
using (ITransaction transaction = session.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
{
try
{
result = (T)session.Get(typeof(T), id);
transaction.Commit();
}
finally
{
if (transaction.IsActive)
transaction.Rollback();
}
}
return result;
}
public IQueryable<T> Find()
{
return SessionBuilder.GetSession().Query<T>();
}
}
Use an interface.
public class IAccountRespository
{
public Account LoadAccountByUsername(String Username);
public void DeleteAccont(Account a);
public void SaveAccont(Account a);
.
.
.
...more methods
}
then you implement this interface on every data access object (ef,mongdb, etc. etc).
In your business logic code you use just the interface and not the acual object.
i use the factory pattern to create the data access objects, but you can use every IoC pattern.