Do I need a Repository Class if I have a Service class and IRepository? - asp.net-mvc-3

After reading, this question. I figured I need to look over my structure to avoid redundant code.
My current structure is Controller -> Repository -> IRepository.
The repository looks like this:
public class UserRepository : IUserRepository, IDisposable
{
private StudentSchedulingEntities _context;
public UserRepository(StudentSchedulingEntities context)
{
if (context == null)
throw new ArgumentNullException("context");
_context = context;
}
public IEnumerable<User> GetUsers()
{
return _context.Users.ToList();
}
public User GetUserByID(int id)
{
return _context.Users.Find(id);
}
public void InsertStudent(User user)
{
_context.Users.Add(user);
}
public void DeleteStudent(int userID)
{
User usr = _context.Users.Find(userID);
_context.Users.Remove(usr);
}
public void UpdateStudent(User user)
{
_context.Entry(user).State = EntityState.Modified;
}
public void Save() {
_context.SaveChanges();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_context != null)
{
_context.Dispose();
_context = null;
}
}
}
}
My IRepository looks like this:
public interface IUserRepository : IDisposable
{
IEnumerable<User> GetUsers();
User GetUserByID(int userID);
void InsertStudent(User user);
void DeleteStudent(int userID);
void UpdateStudent(User user);
void Save();
}
I want to avoid doing this again in the service layer. Do I need the Repository Class or should I just implement the Service Layer in replacement of the Repository?

Your service layer won't need any repository implementations, it will simply use a repository to lookup a user, add/edit/delete a user, etc.
Now, if I can offer a bit of opinion, I'd recommend going with a generic repository. That way, if you need to make new repositories it is really simple. We use nopCommerce, and they use the following code:
public partial interface IRepository<T> where T : BaseEntity
{
T GetById(object id);
void Insert(T entity);
void Update(T entity);
void Delete(T entity);
IQueryable<T> Table { get; }
}
And since it use Entity Framework, this is the implementation:
/// <summary>
/// Entity Framework repository
/// </summary>
public partial class EfRepository<T> : IRepository<T> where T : BaseEntity
{
private readonly IDbContext _context;
private IDbSet<T> _entities;
/// <summary>
/// Ctor
/// </summary>
/// <param name="context">Object context</param>
public EfRepository(IDbContext context)
{
this._context = context;
}
public T GetById(object id)
{
return this.Entities.Find(id);
}
public void Insert(T entity)
{
try
{
if (entity == null)
throw new ArgumentNullException("entity");
this.Entities.Add(entity);
this._context.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
var msg = string.Empty;
foreach (var validationErrors in dbEx.EntityValidationErrors)
foreach (var validationError in validationErrors.ValidationErrors)
msg += string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage) + Environment.NewLine;
var fail = new Exception(msg, dbEx);
//Debug.WriteLine(fail.Message, fail);
throw fail;
}
}
public void Update(T entity)
{
try
{
if (entity == null)
throw new ArgumentNullException("entity");
this._context.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
var msg = string.Empty;
foreach (var validationErrors in dbEx.EntityValidationErrors)
foreach (var validationError in validationErrors.ValidationErrors)
msg += Environment.NewLine + string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
var fail = new Exception(msg, dbEx);
//Debug.WriteLine(fail.Message, fail);
throw fail;
}
}
public void Delete(T entity)
{
try
{
if (entity == null)
throw new ArgumentNullException("entity");
this.Entities.Remove(entity);
this._context.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
var msg = string.Empty;
foreach (var validationErrors in dbEx.EntityValidationErrors)
foreach (var validationError in validationErrors.ValidationErrors)
msg += Environment.NewLine + string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
var fail = new Exception(msg, dbEx);
//Debug.WriteLine(fail.Message, fail);
throw fail;
}
}
public virtual IQueryable<T> Table
{
get
{
return this.Entities;
}
}
private IDbSet<T> Entities
{
get
{
if (_entities == null)
_entities = _context.Set<T>();
return _entities;
}
}
//TODO implement IDisposable interface
}
Now it would be as simple as IRepository<User> or IRepository<Whatever>.

Definitely no to redundant code :-) When you say:
My current structure is Controller -> Repository ->
Is Controller inheriting from Repository? You don't want that either. The repository layer typically interfaces to storage (XML, database, file system, etc) and maps to repository friendly classes. Another layer manages the mapping of the repository layer to your native business/service classes.

Related

Generic ResourceManager/IEnlistmentNotification for Azure Blob Storage operations to achieve 2 phase commit

My application using Azure SQL and Azure Blob Storage for some business requirements, most of the case need to support Atomic Transaction for both DB & Blob, if DB entry fails should rollback Blob as well(go all or no go), for DB side can use TransactionScope but Blob don't have any direct options, so decided to go 2 phase commit with help of IEnlistmentNotification interface, it working as expected but am trying to created common class/implementation to support all operations or at least few most used operations in Blob storage(upload, delete, SetMetadata ...), I don't get any idea about how to create some implementation, is this possible and any code samples available will help me lot.
Resource Manager
public class AzureBlobStorageResourceManager : IEnlistmentNotification, IDisposable
{
private List<AzureBlobStore> _operations;
private bool _disposedValue;
public void EnlistOperation(AzureBlobStore operation)
{
if (_operations is null)
{
var currentTransaction = Transaction.Current;
currentTransaction?.EnlistVolatile(this, EnlistmentOptions.None);
_operations = new List<AzureBlobStore>();
}
_operations.Add(operation);
}
public void Commit(Enlistment enlistment)
{
foreach (var blobOperation in _operations)
{
blobOperation.Dispose();
}
enlistment.Done();
}
public void InDoubt(Enlistment enlistment)
{
foreach (var blobOperation in _operations)
{
blobOperation.RollBack().ConfigureAwait(false);
}
enlistment.Done();
}
public void Prepare(PreparingEnlistment preparingEnlistment)
{
try
{
foreach (var blobOperation in _operations)
{
blobOperation.DoWork().ConfigureAwait(false);
}
preparingEnlistment.Prepared();
}
catch
{
preparingEnlistment.ForceRollback();
}
}
public void Rollback(Enlistment enlistment)
{
foreach (var blobOperation in _operations)
{
blobOperation.RollBack().ConfigureAwait(false);
}
enlistment.Done();
}
public void Dispose() => Dispose(true);
protected virtual void Dispose(bool disposing)
{
if (_disposedValue) return;
if (disposing)
{
foreach (var operation in _operations)
operation.Dispose();
}
_disposedValue = true;
}
~AzureBlobStorageResourceManager() => Dispose(false);
}
Actual Blob Operation
public class AzureBlobStore : IDisposable
{
private string _backupPath;
private readonly string _blobName;
private Stream _content;
private bool _disposedValue;
private BlobClient _blobClient;
public AzureBlobStore(BlobContainerClient containerClient, string blobName, Stream content)
{
(_blobName, _content, _blobClient) = (blobName, content, containerClient.GetBlobClient(blobName));
}
public async Task DoWork()
{
_content.Position = 0;
await _blobClient.UploadAsync(_content).ConfigureAwait(false);
/*
await _blobClient.DeleteAsync(Azure.Storage.Blobs.Models.DeleteSnapshotsOption.IncludeSnapshots).ConfigureAwait(false);
*/
}
public async Task RollBack()
{
// Compensation logic for Upload
await _blobClient.DeleteIfExistsAsync(Azure.Storage.Blobs.Models.DeleteSnapshotsOption.IncludeSnapshots).ConfigureAwait(false);
// Compensation logic for Delete
/* await _blobClient.UploadAsync(_backupPath); */
}
public void Dispose() => Dispose(true);
protected virtual void Dispose(bool disposing)
{
if (_disposedValue) return;
if (disposing)
{
_blobClient.DeleteIfExistsAsync(Azure.Storage.Blobs.Models.DeleteSnapshotsOption.IncludeSnapshots);
}
_disposedValue = true;
}
~AzureBlobStore() => Dispose(false);
}
Code inside /* */ is another one Blob operation, am looking for common way to solve this.

Confused about using dispose in my repository. EF6 MVC

I have been trying to implement a repository pattern in my project. I am not sure if i am using dispose correctly. I took the pattern from the MVA course on entity framework.
My repository
public static bool IsAwesome { get { return true; } }
public class Repository<T> : IDisposable where T : class
{
private ApplicationDbContext db = null;
protected DbSet<T> DbSet { get; set; }
public Repository()
{
db = new ApplicationDbContext();
DbSet = db.Set<T>();
}
public List<T> GetAll()
{
return DbSet.ToList();
}
public T Get(int id)
{
return DbSet.Find(id);
}
public T GetWithString(string id)
{
return DbSet.Find(id);
}
public void Add(T entity)
{
DbSet.Add(entity);
}
public void Update(T entity)
{
DbSet.Attach(entity);
db.Entry(entity);
}
public void SaveChanges()
{
db.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
db.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
Example of imageRepository which inherits from repository
public class ImageRepository : Repository<Image>
{
public Image GetLatest(int vehicleId)
{
return DbSet.FirstOrDefault(p => p.VehicleId == vehicleId);
}
public List<Image> GetImagesByVehicleId(int vehicleId)
{
return DbSet.Where(p => p.VehicleId == vehicleId).ToList();
}
}
Using my repository on top of the controller and disposing in the bottom of my controller
ImageRepository imageRepository = new ImageRepository();
UserRepository userRepository = new UserRepository();
protected override void Dispose(bool disposing)
{
imageRepository.Dispose();
userRepository.Dispose();
base.Dispose(disposing);
}
Will my code handle all unmanaged connections and close them correctly?
Thank you in advance. Im still a bit new to MVC and EF. I am sorry if my question is a bit newbish. My first post in here. So i hope i did not break any rules:)
Add your Dispose code in UnitOfWork,Remove From GenericRepository
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
Context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
Will my code handle all unmanaged connections and close them
correctly?
Apparently yes.
However, you are not quite following the pattern. You don't have to SuppressFinalize as you don't have a finalizer in your class.Have a read about proper implementation of IDisposable Pattern.

Linq executing query generates not supported exception

I'm trying to execute a linq query in an extension method but I am getting the following exception on the ToArray() function call - it seems the query is having issues with my IList somehow, I have tried many different things and googled but fails to see the issue
An exception of type 'System.NotSupportedException' occurred in EntityFramework.SqlServer.dll but was not handled in user code
Additional information: Cannot compare elements of type 'System.Collections.Generic.IList`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'. Only primitive types, enumeration types and entity types are supported.
Code
public static IList<Shared.Poco.DimValue> ToDimValuePocoList(this IQueryable<DAL.DimValue> source)
{
IList<Shared.Poco.DimValue> values = new List<Shared.Poco.DimValue>();
foreach (DAL.DimValue dv in source.ToArray())
{
values.Add(new Shared.Poco.DimValue
{
DimensionId = dv.DimensionID,
DimValueName = dv.DimValueName,
DimValueNo = dv.DimValueNo
});
}
return values;
}
The class the calls the extension looks like this:
public class DimValue : IDimValue
{
private IDimValueRepository _repository;
private IAccessableDimensionValues _accessableDimensionValues;
private IRevision _revision;
public DimValue(IDimValueRepository reposotory, IAccessableDimensionValues accessableDimensionValues, IRevision revision)
{
_repository = reposotory;
_accessableDimensionValues = accessableDimensionValues;
_revision = revision;
}
public IList<Shared.Poco.DimValue> GetDimValueList(int budgetId, Shared.Poco.Dimension dimension, IList<string> dimensionValues, Shared.Poco.User user)
{
IList<Shared.Poco.DimValue> values = new List<Shared.Poco.DimValue>();
int budgetRevisionId = _revision.GetLatesRevision(budgetId);
IList<string> uniqueAccessableUBLValues = _accessableDimensionValues.GetUniqueAccessableDimensionValues(dimension, user.UserId, budgetRevisionId);
if (dimensionValues != null && dimensionValues.Count > 0)
{
uniqueAccessableUBLValues = dimensionValues;
}
return _repository.GetDimValueList(budgetId, dimension.ToString(), uniqueAccessableUBLValues, user).ToDimValuePocoList();
}
The implementation of the injected repository class inherits from the following base repository class
public interface IRepository<T>
{
void Insert(T entity);
void Delete(T entity);
IQueryable<T> SearchFor(Expression<Func<T, bool>> predicate);
IQueryable<T> GetAll();
T GetById(int id);
}
public class Repository<T> : IRepository<T> where T : class
{
protected DbSet<T> DbSet;
public Repository(DbContext dataContext)
{
DbSet = dataContext.Set<T>();
}
#region IRepository<T> Members
public void Insert(T entity)
{
DbSet.Add(entity);
}
public void Delete(T entity)
{
DbSet.Remove(entity);
}
public IQueryable<T> SearchFor(Expression<Func<T, bool>> predicate)
{
return DbSet.Where(predicate);
}
public IQueryable<T> GetAll()
{
return DbSet;
}
public T GetById(int id)
{
return DbSet.Find(id);
}
#endregion
}
Repository implementation
public class DimValueRepository : Repository<DimValue>, IDimValueRepository
{
public DimValueRepository(KonstruktEntities context) : base(context) { }
public IQueryable<DimValue> GetDimValueList(int budgetId, string dimensionId, IList<string> dimensionFilter, Shared.Poco.User user)
{
return this.SearchFor(dv => dv.BudgetID == budgetId && dv.DimensionID == dimensionId &&
(dimensionFilter == null || dimensionFilter.Count == 0 || dimensionFilter.Contains(dv.DimValueNo)));
}
public IQueryable<DimValue> GetDimValueList(Shared.Poco.Dimension dimension, string startsWith, Shared.Poco.User user)
{
return this.SearchFor(dv=>dv.DimensionID == dimension.ToString() &&
dv.DimValueNo.StartsWith(startsWith));
}
}
EDIT
It's failing on the following row in the ToDimValuePocoList function:
foreach (DAL.DimValue dv in source.ToArray())
Here is the row calling the extension in the DimValue class
return _repository.GetDimValueList(budgetId, dimension.ToString(), uniqueAccessableUBLValues, user).ToDimValuePocoList();
Answered by #Will in the comment above, i.e. cannot use dimensionFilter in my predicate. So I moved that logic outside of the predicate.

"The type IUnitOfWork does not have an accessible constructor" with Umbraco 6.1, UmbracoApiController (Web API) & Dependency Injection (Unity)

I am using Umbraco 6.1 with an UmbracoApiController which has a IUnitOfWork injected into it's constructor. To inject the dependencies, I am using Unity, like I have in the past with standard Web API projects. Normally, I set unity up in the Global.asax.cs. As Umbraco does not have this I have created my own UmbracoEvents handler, which inherits from IApplicationEventHandler, and has the methods:
OnApplicationInitialized
OnApplicationStarting
OnApplicationStarted
ConfigureApi
In the OnApplicationStarted method I set up my EF database, db initializer etc and call ConfigureApi to set up Unity. My OnApplication Started and ConfigureApi methods looks like this:
public void OnApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
_applicationContext = applicationContext;
_umbracoApplication = umbracoApplication;
_contentService = ApplicationContext.Current.Services.ContentService;
this.ConfigureApi(GlobalConfiguration.Configuration);
Database.SetInitializer(null);
PropertySearchContext db = new PropertySearchContext();
db.Database.Initialize(true);
}
private void ConfigureApi(HttpConfiguration config)
{
var unity = new UnityContainer();
unity.RegisterType<PropertiesApiController>();
unity.RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager());
config.DependencyResolver = new IoCContainer(unity);
}
My Controller code:
public class PropertiesApiController : UmbracoApiController
{
private readonly IUnitOfWork _unitOfWork;
public PropertiesApiController(IUnitOfWork unitOfWork)
{
if(null == unitOfWork)
throw new ArgumentNullException();
_unitOfWork = unitOfWork;
}
public IEnumerable GetAllProperties()
{
return new[] {"Table", "Chair", "Desk", "Computer", "Beer fridge"};
}
}
My Scope Container/IoC Container code: (as per http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver)
public class ScopeContainer : IDependencyScope
{
protected IUnityContainer container;
public ScopeContainer(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
}
public object GetService(Type serviceType)
{
if (container.IsRegistered(serviceType))
{
return container.Resolve(serviceType);
}
else
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
if (container.IsRegistered(serviceType))
{
return container.ResolveAll(serviceType);
}
else
{
return new List<object>();
}
}
public void Dispose()
{
container.Dispose();
}
}
public class IoCContainer : ScopeContainer, IDependencyResolver
{
public IoCContainer(IUnityContainer container)
: base(container)
{
}
public IDependencyScope BeginScope()
{
var child = this.container.CreateChildContainer();
return new ScopeContainer(child);
}
}
My IUnitOfWork code:
public interface IUnitOfWork : IDisposable
{
GenericRepository<Office> OfficeRepository { get; }
GenericRepository<Property> PropertyRepository { get; }
void Save();
void Dispose(bool disposing);
void Dispose();
}
My UnitOfWork implementation:
public class UnitOfWork : IUnitOfWork
{
private readonly PropertySearchContext _context = new PropertySearchContext();
private GenericRepository<Office> _officeRepository;
private GenericRepository<Property> _propertyRepository;
public GenericRepository<Office> OfficeRepository
{
get
{
if (this._officeRepository == null)
{
this._officeRepository = new GenericRepository<Office>(_context);
}
return _officeRepository;
}
}
public GenericRepository<Property> PropertyRepository
{
get
{
if (this._propertyRepository == null)
{
this._propertyRepository = new GenericRepository<Property>(_context);
}
return _propertyRepository;
}
}
public void Save()
{
_context.SaveChanges();
}
private bool disposed = false;
public virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
_context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
I have used unity/DI with MVC4/WebAPI controllers and this implementation of UnitOfWork many times before without issue, so I'm thinking it's Umbraco specific.
I have also debugged the application and made sure that it hits OnApplicationStarted and that its parameters are not null.
The GetAllProperties method in the controller is just a test method to make sure it is all working fine, however, when I try and access this action I get the error:
"The type IUnitOfWork does not have an accessible constructor"
Does anyone have experience with using Umbraco 6.1 and it's UmbracoApiController with dependency injection/Unity?
Also, on an unrelated note, is there a way to return JSON instead of XML in the action? In Web API you would just define the formatter in the WebApi.config but there is none in Umbraco.
Thanks,
Justin
In case you haven't found a solution to your problem? Download this nuget package and right after building your unity container:
GlobalConfiguration.Configuration.DependencyResolver =
new Unity.WebApi.UnityDependencyResolver(Bootstrapper.Container);
Notice the namespace which is different than Unity.Mvc4.UnityDependencyResolver.

Entity Framework throwing error when updating records

Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
I get this error, but I am the only person using the database. I am using Entity Framework 4.1 with DBContext.
I am updating my records and SQL Profiler is showing a queue being sent in. What could be the causes of this issue?
The post:
[HttpPost]
public ActionResult EditUser(User user)
{
uow.UserRepository.Update(user);
uow.Save();
return RedirectToAction("Index", "User");
}
On this call:
public void Save()
{
_context.SaveChanges();
}
This is how it is attached
public virtual void Update(TEntity entityToUpdate)
{
dbSet.Attach(entityToUpdate);
context.Entry(entityToUpdate).State = EntityState.Modified;
}
Update:
public class UnitOfWork : IDisposable
{
private StudentSchedulingEntities _context = new StudentSchedulingEntities();
private GenericRepository<User> userRepository;
private GenericRepository<UserRole> userRoleRepository;
private bool disposed = false;
public GenericRepository<User> UserRepository
{
get
{
if (this.userRepository == null)
{
this.userRepository = new GenericRepository<User>(_context);
}
return userRepository;
}
}
public GenericRepository<UserRole> UserRoleRepository
{
get
{
if (this.userRoleRepository == null)
{
this.userRoleRepository = new GenericRepository<UserRole>(_context);
}
return userRoleRepository;
}
}
public void Save()
{
_context.SaveChanges();
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
_context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
The ID field must be there in order to update the information properly. Otherwise, it will be throw a null. (I forgot to put the hidden field for ID in)

Resources