I am confused about DI and these dependency containers.
Can't inject my dbcontext and services into my application.
Unhandled exception. System.ArgumentException: Cannot instantiate implementation type 'Server.Logic.Registration.IRegistrationService' for service type 'Server.Logic.Registration.IRegistrationService'.
Stack trace:
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.Populate() in Microsoft.Extensions.DependencyInjection.dll:token 0x600007a+0xea
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory..ctor(IEnumerable`1 descriptors) in Microsoft.Extensions.DependencyInjection.dll:token 0x6000079+0x3e
Multiple guides on the internet are about single IRepository and a single table.
While I my Repository is generic.
IRepository
public interface IRepository<TEntity> where TEntity : class
{
void Create(TEntity item);
TEntity FindById(int id);
IEnumerable<TEntity> Get();
IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> predicate);
void Remove(TEntity item);
void Update(TEntity item);
}
GenericRepository
public class GenericRepository<TEntity> : IRepository<TEntity>, IDisposable where TEntity : class
{
public DbContext _context { get; set; }
public DbSet<TEntity> _dbSet { get; set; }
public GenericRepository(DbContext context)
{
_context = context;
_dbSet = context.Set<TEntity>();
}
public IEnumerable<TEntity> Get()
{
return _dbSet.AsNoTracking().ToList();
}
public IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> predicate)
{
return _context.Set<TEntity>().Where(predicate).ToList();
}
public TEntity FindById(int id)
{
return _dbSet.Find(id);
}
public void Create(TEntity item)
{
_dbSet.Add(item);
_context.SaveChanges();
}
public void Update(TEntity item)
{
_context.Entry(item).State = EntityState.Modified;
_context.SaveChanges();
}
public void Remove(TEntity item)
{
_dbSet.Remove(item);
_context.SaveChanges();
}
protected void Dispose(bool disposing)
{
if (disposing)
{
if (_context != null)
{
_context.Dispose();
_context = null;
}
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
In many points of my code, I have to use multiple entites of these Generic Repository.
Because I have around 9 tables. And sometimes I have to take info from more than one table.
Here is my service and it's interface, which is realizing my logic.
public interface IRegistrationService
{
public JsonResult GetAll();
public JsonResult GetById(int id);
}
And my Registration Service
public class RegistrationService : IRegistrationService
{
public IRegistrationService _sender;
private GenericRepository<RegistrationCountByMonth> _repoWithDates { get; set; }
private GenericRepository<RegistrationCountByDevicesAndMonth> _repoWithDataAndDevices { get; set; }
private GenericRepository<DeviceType> _deviceTypes { get; set; }
public RegistrationService(GenericRepository<RegistrationCountByMonth> dates,
GenericRepository<RegistrationCountByDevicesAndMonth> devices,
GenericRepository<DeviceType> deviceTypes, IRegistrationService sender)
{
_repoWithDates = dates;
_repoWithDataAndDevices = devices;
_deviceTypes = deviceTypes;
_sender = sender;
}
public JsonResult GetAll()
{
var crudeInfoByMonth = _repoWithDates.Get();
List<CleanByMonth> infoListToReturn = new List<CleanByMonth>();
foreach (var crudeInfo in crudeInfoByMonth)
{
if (crudeInfo.Month == DateTime.Today.Month)
{
CleanByMonth item = new CleanByMonth
{
year = crudeInfo.Year, month = crudeInfo.Month, registeredUsers = crudeInfo.NumberOfUsers
};
infoListToReturn.Add(item);
}
}
return new JsonResult(infoListToReturn);
}
public JsonResult GetById(int id)
{
int year = MySimpleMath.TakeNDigits(id, 4);
int month = int.Parse((id % 100).ToString().PadLeft(2, '0'));
var registrationByDeviceAndMonth = _repoWithDataAndDevices.Get();
CleanWithBoth returnInfo = new CleanWithBoth();
returnInfo.year = year;
returnInfo.month = (byte)month;
returnInfo.registeredUsers = 0;
List<Provision> specificData = new List<Provision>();
var devices = _deviceTypes.Get();
foreach (var dataSet in registrationByDeviceAndMonth.Where(x => x.Year == year && x.Month == month))
{
Provision info = new Provision();
info.type = devices.First(x => x.DeviceId == dataSet.DeviceType.Value).DeviceName;
info.value = dataSet.NumberOfUsers;
specificData.Add(info);
if (dataSet.NumberOfUsers != null)
{
returnInfo.registeredUsers += dataSet.NumberOfUsers.Value;
}
}
returnInfo.registeredDevices = specificData;
return new JsonResult(returnInfo);
}
}
Here is how I am using the asp.net default dependency injection.
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IRegistrationService>();
services.AddTransient<IRegistrationService, RegistrationService>();
services.AddTransient<RegistrationService>();
services.AddScoped(typeof(IRepository<>), typeof(GenericRepository<>));
services.AddDbContext<ApplicationContext>(
options => options.UseSqlServer("name=ConnectionStrings:LocalDB"));
services.AddControllers();
}
I can't understand where is my error. Should I maybe somewhere use "new" ?
Please, can you point me to a solution. I really want to understand DI.
But my projects are not that simple as all of those guides..
Maybe I should move myself to Ninject, instead of the default asp.net DI tools ?
Try removing the following lines:
services.AddTransient();
services.AddTransient();
Related
I am developing a project in layered architecture to improve myself.Now let me show you my layers.
public class EfEntityRepositoryBase<TEntity, TContext> : IEntityRepository<TEntity>
where TEntity : class, IEntity, new()
where TContext : DbContext, new()
{
public void Add(TEntity entity)
{
using (var context = new TContext())
{
var addedEntity = context.Entry(entity);
addedEntity.State = EntityState.Added;
context.SaveChanges();
}
}
public async void AddAsync(TEntity entity)
{
using (var context = new TContext())
{
context.Add(entity);
await context.SaveChangesAsync();
}
}
public void Delete(TEntity entity)
{
using (var context = new TContext())
{
var removedEntity = context.Entry(entity);
removedEntity.State = EntityState.Deleted;
context.SaveChanges();
}
}
public TEntity Get(Expression<Func<TEntity, bool>> filter = null)
{
using (var context = new TContext())
{
return context.Set<TEntity>().SingleOrDefault(filter);
}
}
public List<TEntity> GetList(Expression<Func<TEntity, bool>> filter = null)
{
using (var context = new TContext())
{
return filter == null
? context.Set<TEntity>().ToList()
: context.Set<TEntity>().Where(filter).ToList();
}
}
public void Update(TEntity entity)
{
using (var context = new TContext())
{
var updatedEntity = context.Entry(entity);
updatedEntity.State = EntityState.Modified;
context.SaveChanges();
}
}
}
This is my data access layer.
public class IProductManager : IProductService
{
private IProductDal _productDal;
public IProductManager(IProductDal productDal)
{
_productDal = productDal;
}
public void Add(Product product)
{
_productDal.Add(product);
}
public void AddAsync(Product product)
{
_productDal.AddAsync(product);
}
public void Delete(int productId)
{
_productDal.Delete(new Product { ProductId = productId });
}
public List<Product> GetAll()
{
return _productDal.GetList();
}
public List<Product> GetByCategoryId(int categoryId)
{
return _productDal.GetList(p => p.CategoryId == categoryId || categoryId== 0);
}
public Product GetById(int productId)
{
return _productDal.Get(p => p.ProductId == productId);
}
public void Update(Product product)
{
_productDal.Update(product);
}
}
This is my business layer.
When I try to write generic, some things are missing, so I don't understand much.
Now I want to ask, how should I write the following code, because I'm new, I couldn't do it.
List<Product> products = context.Products.Include(x => x.Photos).ToList();
I can post it anywhere you want.
If I understood you correctly, you want to change
List<Product> products = context.Products.Include(x => x.Photos).ToList()
to something like:
List<T> entities = context.Set<T>().Include(x => x.Photos).ToList()
You can not. Let's say you want to use this generic class for your Category model and your Category model does not have Photos property.
I would suggest to make a generic Repository class for all CRUD operations
public interface IBaseRepository<T> where T : class
{
Task AddAsync(T entity);
void Delete(T entity);
void Update(T entity);
Task<IEnumerable<T>> GetAllAsync();
Task<T> FindAsync(Expression<Func<T, bool>> expression);
}
And implementing:
public class BaseRepository<T> : IBaseRepository<T> where T : class
{
protected readonly AppDbContext _context;
private DbSet<T> _dbSet;
public DbSet<T> DbSet => _dbSet ??= _context.Set<T>();
public BaseRepository(AppDbContext context)
{
_context = context;
}
public async Task AddAsync(T entity)
{
await DbSet.AddAsync(entity);
}
public void Delete(T entity)
{
DbSet.Remove(entity);
}
public void Update(T entity)
{
DbSet.Update(entity);
}
// here we made vitrual, this gaves us opportunity to override this method
public virtual async Task<IEnumerable<T>> GetAllAsync()
{
return await DbSet.ToListAsync();
}
public virtual async Task<T> FindAsync(Expression<Func<T, bool>> expression)
{
return await DbSet.Where(expression).FirstOrDefaultAsync();
}
}
Your Product Repository:
public class ProductRepository : BaseRepository<Product>
{
public ProductRepository(AppDbContext context) : base(context)
{
}
public async override Task<IEnumerable<Product>> GetAllAsync()
{
return await DbSet.Include(p => p.Photos).ToListAsync();
}
}
I've got an error while start my application with GenericRepository. (No database provider has been configured for this DbContext.).
How can i modify mine GenericRepository to be able to resolve that? Here's my codes:
IRepository.cs
public interface IRepository<TEntity> where TEntity : class
{
/*void Delete(TEntity entityToDelete);
void Delete(object id);*/
IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "");
TEntity GetById(object id);
Task<TEntity> GetByIdAsync(object id);
/*IEnumerable<TEntity> GetWithRawSql(string query,
params object[] parameters);*/
void Insert(TEntity entity);
TEntity Update(long id, Action<TEntity> action);
}
Generic Repository.cs
public class GenericRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
internal Context context;
internal DbSet<TEntity> dbSet;
public GenericRepository(Context context)
{
this.context = context;
this.dbSet = context.Set<TEntity>(); // here's the error (No database provider...)
}
public virtual IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
IQueryable<TEntity> query = dbSet;
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
public virtual TEntity GetById(object id)
{
return dbSet.Find(id);
}
public async Task<TEntity> GetByIdAsync(object id)
{
return await dbSet.FindAsync(id);
}
public virtual void Insert(TEntity entity)
{
dbSet.Add(entity);
context.SaveChanges();
}
public virtual void Remove(object id)
{
TEntity entityToDelete = GetById(id);
Remove(entityToDelete);
}
public void Remove(TEntity entityToDelete)
{
if (context.Entry(entityToDelete).State == EntityState.Detached)
{
dbSet.Attach(entityToDelete);
}
dbSet.Remove(entityToDelete);
}
public virtual void Update(TEntity entity)
{
dbSet.Attach(entity);
context.Entry(entity).State = EntityState.Modified;
}
public TEntity Update(long key, Action<TEntity> action)
{
var model = dbSet.Find(key);
if(model != null)
{
Update(model);
action(model);
}
return model;
}
}
DependencyResolver.cs
public class DependencyResolver
{
public IServiceProvider ServiceProvider { get; }
public DependencyResolver()
{
// Set up Dependency Injection
IServiceCollection services = new ServiceCollection();
ConfigureServices(services);
ServiceProvider = services.BuildServiceProvider();
}
private void ConfigureServices(IServiceCollection services)
{
services.AddTransient(typeof(IRepository<>), typeof(GenericRepository<>));
// Register DbContext class
services.AddTransient(provider =>
{
var configService = provider.GetService<IConfigurationService>();
//var connectionString = configService.GetConfiguration().GetConnectionString("uRP");
var optionsBuilder = new DbContextOptionsBuilder<Context>();
optionsBuilder.UseMySql("server=localhost;database=uRP;user=root;password=;", builder => builder.MigrationsAssembly(typeof(Context).GetTypeInfo().Assembly.GetName().Name));
return new Context(optionsBuilder.Options);
});
services.AddScoped<IAccountService, AccountService>();
services.AddScoped<IUnitOfWork, UnitOfWork.UnitOfWork>();
}
}
Context.cs
public class Context : DbContext
{
public Context(DbContextOptions<Context> options) : base(options)
{
}
public Context()
{
}
public DbSet<AccountModel> Players { get; set; }
public DbSet<CharacterModel> Characters { get; set; }
}
And ContextTimeDesignFactory.cs
class ContextDesignTimeFactory : IDesignTimeDbContextFactory<Context>
{
public Context CreateDbContext(string[] args)
{
var resolver = new DependencyResolver();
return resolver.ServiceProvider.GetService(typeof(Context)) as Context;
}
}
There are all good. I've got an IAccountRepository, and ICharacterRepository and it's work good. How i can set the DbContextOptions in GenericRepository.cs?
Seems like a mistake with registration of Context.
You have DependencyResolver which used in ContextDesignTimeFactory. But how do you register Context within application?
When I try to register Context like this:
// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
...
services.AddTransient(provider =>
{
var optionsBuilder = new DbContextOptionsBuilder<Context>();
optionsBuilder.UseMySql(
"server=localhost;database=uRP;user=root;password=;",
builder => builder.MigrationsAssembly(typeof(Context).GetTypeInfo().Assembly.GetName().Name));
return new Context(optionsBuilder.Options);
});
services.AddTransient(typeof(IRepository<>), typeof(GenericRepository<>));
}
there is no errors with resolving GenericRepository.
But when I change registration to
// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
...
services.AddTransient<Context>();
services.AddTransient(typeof(IRepository<>), typeof(GenericRepository<>));
}
I've got exactly same exception at the same place.
Hope it help
P.S. For DbContext registration has a specific method AddDbContext
So Im cant get it right and I`m trying from about 5 hours and nothing. If some can help I will be greatfull.
So here is my code
MyContextFile:
public class InventoryManagerContext : IdentityDbContext<ApplicationUser>, IInventoryManagerContext
{
public InventoryManagerContext()
: base("name=InventoryManager")
{
}
public virtual IDbSet<Cloth> Clothes { get; set; }
public static InventoryManagerContext Create()
{
return new InventoryManagerContext();
}
}
My Data file:
public class InventoryManagerData: IInventoryManagerData
{
private readonly DbContext context;
private readonly Dictionary<Type, object> repositories = new Dictionary<Type, object>();
public InventoryManagerData()
: this(new InventoryManagerContext())
{
}
public InventoryManagerData(DbContext context)
{
this.context = context;
}
private IRepository<T> GetRepository<T>() where T : class
{
if (!this.repositories.ContainsKey(typeof(T)))
{
var type = typeof(GenericRepository<T>);
this.repositories.Add(typeof(T), Activator.CreateInstance(type, this.context));
}
return (IRepository<T>)this.repositories[typeof(T)];
}
public int SaveChanges()
{
return this.context.SaveChanges();
}
public void Dispose()
{
this.context.Dispose();
}
public IRepository<Cloth> Clothes
{
get { return this.GetRepository<Cloth>(); }
}
}
and Generic Repository Fail:
public class GenericRepository<T> : IRepository<T> where T : class
{
//public GenericRepository()
// : this(new InventoryManagerContext())
//{
//}
public GenericRepository(DbContext context)
{
if (context == null)
{
throw new ArgumentException("An instance of DbContext is required to use this repository.", "context");
}
this.Context = context;
this.DbSet = this.Context.Set<T>();
}
protected IDbSet<T> DbSet { get; set; }
protected DbContext Context { get; set; }
public virtual IQueryable<T> All()
{
return this.DbSet.AsQueryable();
}
public virtual T GetById(int id)
{
return this.DbSet.Find(id);
}
public virtual void Add(T entity)
{
DbEntityEntry entry = this.Context.Entry(entity);
if (entry.State != EntityState.Detached)
{
entry.State = EntityState.Added;
}
else
{
this.DbSet.Add(entity);
}
}
public virtual void Update(T entity)
{
DbEntityEntry entry = this.Context.Entry(entity);
if (entry.State == EntityState.Detached)
{
this.DbSet.Attach(entity);
}
entry.State = EntityState.Modified;
}
public virtual void Delete(T entity)
{
DbEntityEntry entry = this.Context.Entry(entity);
if (entry.State != EntityState.Deleted)
{
entry.State = EntityState.Deleted;
}
else
{
this.DbSet.Attach(entity);
this.DbSet.Remove(entity);
}
}
public virtual void Delete(int id)
{
var entity = this.GetById(id);
if (entity != null)
{
this.Delete(entity);
}
}
public virtual void Detach(T entity)
{
DbEntityEntry entry = this.Context.Entry(entity);
entry.State = EntityState.Detached;
}
}
So Im trying to make Fake Context and the pass it to the Data class, but without success. in the Test controller Im trying to use MOQ, in a example like this:
[TestMethod]
public void Index_ShouldPass()
{
var mockContext = new Mock<IInventoryManagerContext>();
foreach (var cloth in clothes)
{
mockContext.Object.Clothes.Add(cloth);
}
var mockMenuRepository = new Mock<IRepository<Cloth>>(mockContext.Object);
var mockUnitOfWork = new Mock<InventoryManagerData>(mockContext.Object);
mockUnitOfWork.Setup(e => e.Clothes).Returns(mockMenuRepository.Object);
var menuItems = mockUnitOfWork.Object.Clothes.All();
Assert.AreEqual(4, menuItems.Count());
}
So I have interfaces as well IInventoryManagerContext, IInventoryManagerData and IRepository with all Add, Remove signatures.
For data I have really simple List of for Cloth Objects. and tried to add them o the context with loop. But my latest error is:
Test error:
Message: Test method InventoryManager.Tests.Controllers.HomeControllerTests.Index_ShouldPass threw exception:
System.NullReferenceException: Object reference not set to an instance of an object.
Kind of desperate already..
I have a repository pattern that I am using for an application. Everything is working perfectly today. However, I want to add ability to include relations to other models.
Here is my current IRepository
public interface IRepository<TModel>
where TModel : class
{
// Get records by it's primary key
TModel Get(int id);
// Get all records
IEnumerable<TModel> GetAll();
// Get all records matching a lambda expression
IEnumerable<TModel> Find(Expression<Func<TModel, bool>> predicate);
// Get the a single matching record or null
TModel SingleOrDefault(Expression<Func<TModel, bool>> predicate);
// Add single record
TModel Add(TModel entity);
// Add multiple records
IEnumerable<TModel> AddRange(IEnumerable<TModel> entities);
// Remove records
void Remove(TModel entity);
// remove multiple records
void RemoveRange(IEnumerable<TModel> entities);
}
Here is my Entity implementation
public class EntityRepository<TEntity> : IRepository<TEntity>
where TEntity : class
{
protected readonly DbContext Context;
protected readonly DbSet<TEntity> DbSet;
public EntityRepository(DbContext context)
{
Context = context;
DbSet = context.Set<TEntity>();
}
public TEntity Get(int id)
{
return DbSet.Find(id);
}
public IEnumerable<TEntity> GetAll()
{
return DbSet.ToList();
}
public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.Where(predicate);
}
public TEntity SingleOrDefault(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.SingleOrDefault(predicate);
}
public TEntity Add(TEntity entity)
{
TEntity record = DbSet.Add(entity);
return record;
}
public IEnumerable<TEntity> AddRange(IEnumerable<TEntity> entities)
{
IEnumerable<TEntity> records = DbSet.AddRange(entities);
return records;
}
public void Remove(TEntity entity)
{
DbSet.Remove(entity);
}
public void RemoveRange(IEnumerable<TEntity> entities)
{
DbSet.RemoveRange(entities);
}
Now, I want to add another method to allow me to handle lazy loading.
In another words, I want to be able to do something like this
using(var con = new UnitOfWork())
{
var task = con.Tasks.With(x => x.Owner).GetAll();
}
Here in my Unit of work class
public sealed class UnitOfWork : IUnitOfWork
{
private bool Disposed = false;
private readonly ModuleContext Context;
public ITaskRepository Tasks { get; private set; }
public UnitOfWork(ModuleContext context)
{
Context = context;
Tasks = new TaskRepository(Context);
}
public int Save()
{
return Context.SaveChanges();
}
public void Dispose()
{
Dispose(true);
}
private void Dispose(bool disposing)
{
if (!Disposed && Context != null && disposing)
{
Context.Dispose();
}
Disposed = true;
}
}
Here is my task model
public class Task
{
public string Name { get; set; }
[ForeignKey("Client")]
public int ClientId { get; set; }
[ForeignKey("Owner")]
public int? OwnerId { get; set; }
public virtual Client Client { get; set; }
public virtual User Owner { get; set; }
}
How can I add a way to allow me to include relations to different models?
Add an overload for your methods to the repository interface to accept a list of possible include-expressions. E.g.
public IEnumerable<TEntity> FindAll(params Expression<Func<TEntity,object>>[] includes)
{
var query = DbSet;
foreach (var include in includes)
{
query = query.Include(include);
}
return query.ToList();
}
And then you can just write:
uow.Tasks.GetAll(t=>t.Owner);
For the filtered case you can do something like this:
public IEnumerable<TEntity> Find(Expression<Func<TEntity,bool>> filter, params Expression<Func<TEntity,object>>[] includes)
{
var query = DbSet;
foreach (var include in includes)
{
query = query.Include(include);
}
return query.Where(filter).ToList();
}
And then you can just write:
uow.Tasks.Find(t=>t.Something==2, t=>t.Owner);
I'm trying to do a generic Db cotext helper\manager so I can use it as a dll in many projects with different data bases.
I tried to use it with one of my projects but I got confused with the attach and detach in the Add and Edit methods. I'm getting errors as "An entity object cannot be referenced by multiple instances of IEntityChangeTracker."
Could someone help me to get this manager perfect?
public class DbEntityManager<T> : IDisposable where T : class, IEntity
{
public DbContext DbEntities { get; set; }
public virtual int AddNewObject(T objToAdd)
{
DbEntities.Set<T>().Add(objToAdd);
return DbEntities.SaveChanges();
}
public virtual int EditObject(T objToEdit)
{
if (DbEntities.Entry(objToEdit).State == EntityState.Detached)
{
DbEntities.Set<T>().Attach(objToEdit);
DbEntities.Entry(objToEdit).State = EntityState.Modified;
}
else
{
DbEntities.Entry(objToEdit).State = EntityState.Modified;
}
return DbEntities.SaveChanges();
}
public virtual int DeleteObject(T objToDelete)
{
DbEntities.Set<T>().Remove(objToDelete);
return DbEntities.SaveChanges();
}
public virtual List<T> GetAllList()
{
return DbEntities.Set<T>().ToList();
}
public virtual T GetObjectById(int id)
{
return DbEntities.Set<T>().AsEnumerable().SingleOrDefault(x => x.Id == id);
}
public DbEntityManager(DbContext db)
{
DbEntities = db;
}
public void Dispose()
{
this.Dispose();
}
}
EDIT: Trying to explain better what I'm reffering.
The IEntity is an interface just to be able to use the GetObjectById function:
public interface IEntity
{
int Id { get; }
}
Here is an example of a class:
public partial class Address : IEntity
{
public Address()
{
this.Customers = new HashSet<Customer>();
}
public int AddressID { get; set; }
public string Address_Country { get; set; }
public string Address_City { get; set; }
public string Address_Street { get; set; }
public string Address_ZipCode { get; set; }
public virtual ICollection<Customer> Customers { get; set; }
public int Id
{
get { return AddressID; }
}
}
So I can use the code like this: Making a manager just for the class
public class AddressManager : DbEntityManager<Address>
{
public AddressManager()
: base (new MySystemEntities())
{
}
}
And then use it the code (in winform/mvc or whatever):
AddressManager manager = new AddressManager ();
Address address = new Address();
address = manager.GetObjectById(id);
Or:
Address address = new Address();
address.Address_Country = "USA";
manager.AddNewObject(address);
Before I did this I searched the internet to see if a class like this already exist, but I didn't find any. So if anyone knows a class already made with these functions I'd be glad to use it.
I have generally used the Repository along with the UnitOfWork pattern.
Try implementing such a base repository and then created derived entity types using the same.
That will help keep your code DRY.
public interface IBaseRepository<TEntity> : IDisposable
where TEntity : class
{
void Delete(object id);
void Delete(TEntity entity);
TEntity Find(params object[] keyValues);
void Insert(TEntity entity);
void InsertRange(IEnumerable<TEntity> entities);
IQueryable<TEntity> SelectQuery(string query, params object[] parameters);
void Update(TEntity entity);
void RefreshEntityContext(TEntity entity);
}
Hope this helps!
Edit: Ok, here is an extract of the implementation (similar to how I have implemented it):
namespace ContosoUniversity.DAL
{
public class GenericRepository<TEntity> where TEntity : class
{
internal SchoolContext context;
internal DbSet<TEntity> dbSet;
public GenericRepository(SchoolContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
IQueryable<TEntity> query = dbSet;
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
public virtual TEntity GetByID(object id)
{
return dbSet.Find(id);
}
public virtual void Insert(TEntity entity)
{
dbSet.Add(entity);
}
public virtual void Delete(object id)
{
TEntity entityToDelete = dbSet.Find(id);
Delete(entityToDelete);
}
public virtual void Delete(TEntity entityToDelete)
{
if (context.Entry(entityToDelete).State == EntityState.Detached)
{
dbSet.Attach(entityToDelete);
}
dbSet.Remove(entityToDelete);
}
public virtual void Update(TEntity entityToUpdate)
{
dbSet.Attach(entityToUpdate);
context.Entry(entityToUpdate).State = EntityState.Modified;
}
}
}
You can now inherit your repositories from the GenericRepository and have all the basic CRUD operations available.
from,
http://www.asp.net/mvc/tutorials/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
I prefer to do something like the following:
public virtual int EditObject(T objToEdit)
{
var curval = DB.Set<T>().FirstOrDefault(x => x.Id == objToEdit.Id);
//You may want to make all your entities inherit from the same
//baseclass to get Id
if (curval == null)
{
DB.Set<T>.Add(objToEdit);
}
else
{
DB.Entry(curval).CurrentValues.SetValues(objToEdit);
DB.Entry(curval).State = System.Data.Entity.EntityState.Modified;
}
return DB.SaveChanges();
}
it's quite easy to modify this code to work with Models too.
Why reinvent the wheel. Try NRepository, it's a generic repository (yes, another one) with an entity framework extension and uses strategies for reuse rather then service methods.Plus its fully testable without mocks.
IQueryRepository queryRepository = new EntityFrameworkQueryRepository(new YourDbContext()) ;
var address = queryRepository.GetEntity<Address>(
p => p.AddressID == 2,
new AsNoTrackingQueryStrategy(),
new EagerLoadingQueryStrategy<Address>(
p => p.Customers));
Or to add entities as well as just use :
IRepository repository = new EntityFrameworkRepository(new YourDbContext()) ;
var address = new Address{ Address_City = "Leeds" };
repository.Add(address);
repository.Save()
N.B. Don't forget to inject in your repositories :)
entity framework already use repository and unit of work design pattern, no need for an helpers to work with that framework