Refactor IUnitOfWork - asp.net-mvc

Premisse:
I am folowing IUnitOfWork Patterns I created a Base class with my methods to persist data.
My Problem:
I found a problem to write a method Next Number of table from SQLServer, because of this, I am repeating this method in every class .
Classes:
BaseContext Class:
public class BaseContext<T> : DbContext where T : class
{
public DbSet<T> DbSet
{
get;
set;
}
public BaseContext() : base("DefaultConnection")
{
Database.SetInitializer<BaseContext<T>>(null);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
// Class Mapping from IMapping
var typesToMapping = (from x in Assembly.GetExecutingAssembly().GetTypes()
where x.IsClass && typeof(IMapping).IsAssignableFrom(x)
select x).ToList();
foreach (var mapping in typesToMapping)
{
dynamic mappingClass = Activator.CreateInstance(mapping);
modelBuilder.Configurations.Add(mappingClass);
}
}
public virtual void ChangeObjectState(object model, EntityState state)
{
((IObjectContextAdapter)this)
.ObjectContext
.ObjectStateManager
.ChangeObjectState(model, state);
}
// Implement IUnitOfWork
public virtual int Save(T model)
{
this.DbSet.Add(model);
this.ChangeObjectState(model, EntityState.Added);
return this.SaveChanges();
}
public virtual int Update(T model, int id)
{
var entity = DbSet.Find(id);
this.Entry(entity).CurrentValues.SetValues(model);
return this.SaveChanges();
}
public virtual void Delete(T model)
{
var entry = this.Entry(model);
if (entry.State == EntityState.Detached)
this.DbSet.Attach(model);
this.ChangeObjectState(model, EntityState.Deleted);
this.SaveChanges();
}
public virtual IEnumerable<T> GetAll()
{
return this.DbSet.ToList();
}
public virtual T GetById(object id)
{
return this.DbSet.Find(id);
}
public virtual IEnumerable<T> Where(Expression<Func<T, bool>> expression)
{
return this.DbSet.Where(expression);
}
public IEnumerable<T> OrderBy(Expression<Func<T, bool>> expression)
{
return this.DbSet.OrderBy(expression);
}
}
My method NextNumber in every class:
public class VersionDao : BaseContext<Version>, IUnitOfWork<Version>
{
public int Next() => DbSet.Max(x => x.VersionId) + 1;
}
public class TicketDao : BaseContext<ViewModelTicket> , IUnitOfWork<ViewModelTicket>
{
public int Next() => DbSet.Max(x => x.TicketId) + 1;
}
public class CompanyDao : BaseContext<Company>, IUnitOfWork<Company>
{
public int Next() => DbSet.Max(x => x.CompanyId) + 1;
}
Solicitation:
I need a suggestions to stop repeatition on Next method in every class.
Thank you

There is no need to implement Unit of Work pattern if you are using Entity Framework. If you click F12/Go To Definition on DbContext you'll see the following summary
A DbContext instance represents a combination of the Unit Of Work and
Repository patterns such that it can be used to query from a database
and group together changes that will then be written back to the store
as a unit. DbContext is conceptually similar to ObjectContext.

Related

Update in Entity Framework using IUnitOfWork

I am using Entity Framework and IUnitOfWork to not repeat code, my Add is Ok, the problem is to do Update.
I get this error:
Attaching an entity of type 'ViewModelTicket' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.
I am using this BaseContext class:
public class BaseContext<T> : DbContext where T : class
{
public DbSet<T> DbSet { get; set; }
public BaseContext() : base("DefaultConnection")
{
//Caso a base de dados não tenha sido criada,
//ao iniciar a aplicação iremos criar
Database.SetInitializer<BaseContext<T>>(null);
}
public virtual void ChangeObjectState(object model, EntityState state)
{
//Aqui trocamos o estado do objeto,
//facilita quando temos alterações e exclusões
((IObjectContextAdapter)this)
.ObjectContext
.ObjectStateManager
.ChangeObjectState(model, state);
}
public virtual int Save(T model)
{
this.DbSet.Add(model);
return this.SaveChanges();
}
public virtual int Update(T model)
{
var entry = this.Entry(model);
if (entry.State == EntityState.Detached)
this.DbSet.Attach(model);
this.ChangeObjectState(model, EntityState.Modified);
return this.SaveChanges();
}
public virtual T GetById(object id)
{
return this.DbSet.Find(id);
}
}
The IUnitWork interface:
public interface IUnitOfWork<T> where T : class
{
int Save(T model);
int Update(T model);
void Delete(T model);
IEnumerable<T> GetAll();
T GetById(object id);
int Max();
IEnumerable<T> Where(Expression<Func<T, bool>> expression);
IEnumerable<T> OrderBy(Expression<System.Func<T, bool>> expression);
}
The controller method:
public ActionResult SavedTicket(Models.Ticket.ViewModelTicket ticket)
{
if (ModelState.IsValid)
{
if (this.UnitOfTicket.GetById(ticket.TicketId) == null) {
ticket.TicketId = Convert.ToInt32( UnitOfTicket.Max());
ticket.OpenDateAndTime = DateTime.Now;
this.UnitOfTicket.Save(ticket);
} else {
this.UnitOfTicket.Update(ticket);
}
return RedirectToAction(nameof(NewTicket));
}
else {
return View(nameof(NewTicket), ticket);
}
}
Thank you
EDIT
I solved the problem with this.
public virtual int Update(T model, int id)
{
var entity = DbSet.Find(id);
this.Entry(entity).CurrentValues.SetValues(model);
return this.SaveChanges();
}
Thank you guys for helping me.
Shouldn't you generate the next higher Id when inserting a new entity?
// vvv
ticket.TicketId = Convert.ToInt32( UnitOfTicket.Max() + 1 );

Entity Framework, Unity, and MVC

I have a multi tier application using Entity Framework, MVC and Unity.
The basic setup is like this:
EF Data Access Layer
public class MyDataProvider : DbContext, IMyDataProvider
{
public MyDataProvider(SqlConnection existingConnection, bool contextOwnsConnection)
: base(existingConnection,contextOwnsConnection)
{
((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 60;
Configuration.LazyLoadingEnabled = true;
Configuration.ValidateOnSaveEnabled = true;
Configuration.ProxyCreationEnabled = true;
Configuration.AutoDetectChangesEnabled = true;
}
public new IDbSet<TModel> Set<TModel>() where TModel : class
{
return base.Set<TModel>();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new EmployeeMapping());
base.OnModelCreating(modelBuilder);
}
public abstract class ServiceBase<TModel> : IDisposable, IService<TModel> where TModel : class, IModel
{
[Dependency]
public IMyDataProvider MyDataProvider { get; set; }
...
}
All services inherit from this class
I then inject specific services into the Business Logic Layer like so:
public class GetEmployees
{
[Dependency("EmployeeService")]
public IEmployeeService EmployeeService { get; set;
public IQueryable<Employee> GetAllEmployees()
{
return EmployeeService.GetTable();
}
...
}
In MVC I use a controller factory
public class MyControllerFactory : DefaultControllerFactory
{
private IUnityContainer _container;
public MyControllerFactory(IUnityContainer container)
{
_container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType != null)
{
return _container.Resolve(controllerType) as IController;
}
else
{
return base.GetControllerInstance(requestContext, controllerType);
}
}
Global.asax
private static IUnityContainer InitContainer()
{
IUnityContainer unityContainer = new UnityContainer();
Bootstrapper bootstrapper = new Bootstrapper(unityContainer);
return unityContainer;
}
I pass the instance of UnityContainer into the Bootstrapper class. The Bootstrapper class self registers all assemblies.
In the MVC Controllers, I inject the Business Logic like so:
public class EmployeeController
{
[Dependency("GetEmployees")]
public IBusinessLogic GetEmployees_Operations { get; set; }
public ActionResult EmployeeMain()
{
var employees = GetEmployees_Operations.GetAllEmployees();
...
}
}
This all works great up to a point. Every so often I will get an exception thrown from MyDataProvider class: "EntityConnection can only be constructed with a closed DbConnection". This seems to happen during high use of the MVC site. The exception is simple enough to understand, but how should I go about fixing it?
I found that changing how I instantiate the business logic class from a field on the controller to inside the ActionResult method, I don't recieve the exception.
For example:
public class EmployeeController
{
//[Dependency("GetEmployees")]
//public IBusinessLogic GetEmployees_Operations { get; set; }
public ActionResult EmployeeMain()
{
IBusinessLogic GetEmployees_Operations = _ioc_Bootstrapper.Resolve(typeof(IBusinessLogic), "GetEmployees") as IBusinessLogic;
var employees = GetEmployees_Operations.GetAllEmployees();
...
}
}
Have I completely missed the boat on this and implemented Unity incorrectly?
Bootstrapper code
private void RegisterDAL(String assembly)
{
var currentAssembly = Assembly.LoadFrom(assembly);
var assemblyTypes = currentAssembly.GetTypes();
foreach (var assemblyType in assemblyTypes)
{
...
if (assemblyType.FullName.EndsWith("Provider"))
{
foreach (var requiredInterface in assemblyType.GetInterfaces())
{
if (requiredInterface.FullName.EndsWith("DataProvider"))
{
var typeFrom = assemblyType.GetInterface(requiredInterface.Name);
var typeTo = assemblyType;
var injector = GetInjectorConstructor(assemblyType.Module.Name);
RegisterType(typeFrom, typeTo, false, injector);
}
}
continue;
}
...
}
private InjectionConstructor GetInjectorConstructor(String moduleName)
{
...
connString = String.Concat("Data Source=MySqlServer, ";Initial Catalog=", catalogName, ";Application Name=", applicationName, ";Integrated Security=True; );
var conn = new SqlConnection(connString);
return new InjectionConstructor(conn, true);
}

Generic repository pattern and multiple selects

I am trying to learn the repository pattern and looking at a generic repository I cannot see how to handle customized select statements. For example, using this article the author uses a select by ID and a select all.
public interface IGenericRepository<T> where T:class
{
IEnumerable<T> SelectAll();
T SelectByID(object id);
void Insert(T obj);
void Update(T obj);
void Delete(object id);
void Save();
}
Later the article the IGenericRepository interface is implemented using Northwind. Then that is used to create a Customer controller.
public class CustomerController : Controller
{
private IGenericRepository<Customer> repository = null;
public CustomerController()
{
this.repository = new GenericRepository<Customer>();
}
...
This would handle selecting a list of all Customers or for one Customer by ID but where I get stuck is some more real world examples like "select all Customers for a client" or "select all Customers for a region". Plus, you could have another controller based on a different entity that would filter on different attributes. I assume I'm missing something basic. If the user interface needed to present the Customer entity (or any other entity) by various filters, how would this be done by sticking with one generic repository?
Here you go; to handle any select criteria apart from the Id, you can add Where method
like below
public interface IGenericRepository<T> where T:class
{
IEnumerable<T> SelectAll();
T SelectByID(object id);
IEnumerable<T> Where(Expression<Func<T,bool>> predicate)// this one
void Insert(T obj);
void Update(T obj);
void Delete(object id);
void Save();
}
Now in the Where method implementation do it like this
public IEnumerable<T> Where(Expression<Func<T,bool>> predicate)
{
return _objectSet.Where(predicate).AsEnumerable();
}
Here _objectSet in created in repository constructor like this :
public Repository(ObjectContext context)
{
_context = context;
_objectSet = _context.CreateObjectSet<T>();
}
public CustomerController()
{
_context = new NorthwindEntities();
_reporsitory = new Repository<Customer>(_context);
}
Use of Where method like
reporsitory.Where(c=>c.Country=="Canada").ToList();
For full reference see this project on codeplex (download /browse source code)
https://efgenericrepository.codeplex.com/SourceControl/latest
I think the implementation of the GenericRepository should somehow be able to return the IQueryable of current entity, like adding Get() method.
protected IQueryable<T> Get() // Notice that the access modifier is protected.
{
return table;
}
Then you could just create a derived class from GenericRepository and add a select method that accepts the Filter class.
public class CustomerRepository : GenericRepository<Customer>
{
public IEnumerable<T> SelectAll(CustomerFilter filter){ .. }
}
The filter class contains 2 filters.
public class CustomerFilter
{
public int? ClientId { get; set; }
public int? RegionId { get; set; }
}
Then the SelectAll implementation would be.
public IEnumerable<T> SelectAll(CustomerFilter filter)
{
var query = Get();
if (filter == null)
{
return query;
}
if (filter.ClientId.HasValue)
{
query = query.Where(q => q.ClientId == filter.ClientId.Value);
}
if (filter.RegionId.HasValue)
{
query = query.Where(q => q.RegionId == filter.RegionId.Value);
}
return query;
}
In the controller, calling it like.
public ActionResult Get(int? clientId, int? regionId)
{
var filter = new CustomerFilter { ClientId = clientId, RegionId = regionId };
var customers = _repository.SelectAll(filter);
return View();
}
You might need to see this post as your reference.
An approach I've seen in one asp.net mvc based mission critical app, is to use the generic interface as defined in the question. Then there is an abstract class that implements that interface. And there is one more repository class that inherits the abstract class, which has all methods specific to that class.
public interface IGenericRepository<T> where T:class
{
...
}
public abstract class GenericRepository<T> : IGenericRepository where T:class
{
...
}
And the CustomerRepository class
public class CustomerRepository : GenericRepository<Customer>
{
//add method specific to Customer like select Customers in specific country
}
And in the controller
public class CustomerController : Controller
{
private CustomerRepository repository = null;
public CustomerController()
{
this.repository = new CustomerRepository();
}
...

How to execute function in MVC with Entity Framework?

how to use following function
Generic Function:
public T GetSingle(Expression<Func<T, bool>> whereCondition)
{
return this.ObjectSet.Where(whereCondition).FirstOrDefault<>();
}
Business logic wise:
//Now in the following function i would like to call Generic function.
public TabMasterViewModel GetSingle(Expression<Func<TabMasterViewModel, bool>> whereCondition)
{
_tabmasterRepository.GetSingle( .. what should be here.. );
}
//Calling function from Controller level.
public ActionResult Details(int id)
{
return View(_tabmasterService.GetSingle(x => x.colID == id));
}
I could not able to use the function, please suggest.
_tabmasterRepository.GetSingle( .. what should be here.. );
Thanks,
Imdadhusen
Either you modify your first generic function as
public T GetSingle(Expression<Func<T, bool>> whereCondition)
{
return context.CreateObjectSet<T>().Where(whereCondition).FirstOrDefault();
}
or create a genetic repository
public class RepositoryGeneric<TEntity>
{
public RepositoryGeneric(Context context)
{
Context = context;
}
protected ObjectContext Context { get; private set; }
protected virtual ObjectSet<TEntity> ObjectSet
{
get { return Context.CreateObjectSet<TEntity>(); }
}
public virtual TEntity GetByKey(params object[] keys)
{
return DbSet.Find(keys);
}
public TEntity GetSingle(Expression<Func<TEntity, bool>> whereCondition)
{
return ObjectSet.Where(whereCondition).FirstOrDefault();
}
}
Edit:
using the generic function
TabMasterViewModel model = _tabmasterService.GetSingle(x => x.colID == id);
or using generic repository
var tabmasterRepository = new RepositoryGeneric<TabMasterViewModel>(new Context());
var model = tabmasterRepository.GetSingle(x => x.colID == id);

Norm.MongoException: Connection timeout trying to get connection from connection pool

I'm using Rob's mvc startesite http://mvcstarter.codeplex.com/ with ASP.Net MVC 2, Ninject2, NoRM (http://github.com/atheken/NoRM) and MongoDB. It works so fast and the developpement is even faster but I'm facing a big problem, I at some points, get connection timeout. I can't figure out what I'm doing wrong.
I already asked a question here : I get this error that I don't understand why, using NoRM and Mongo in my MVC project and here http://groups.google.com/group/norm-mongodb/browse_thread/thread/7882be16f030eb29 but I still in the dark.
Thanks a lot for the help!
EDITED*
Here's my MongoSession object :
public class MongoSession : ISession{
private readonly Mongo _server;
public MongoSession()
{
//this looks for a connection string in your Web.config - you can override this if you want
_server = Mongo.Create("MongoDB");
}
public T Single<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression) where T : class {
return _server.GetCollection<T>().AsQueryable().Where(expression).SingleOrDefault();
}
public IQueryable<T> All<T>() where T : class {
return _server.GetCollection<T>().AsQueryable();
}
public void Save<T>(IEnumerable<T> items) where T : class {
foreach (T item in items) {
Save(item);
}
}
public void Save<T>(T item) where T : class {
var errors = DataAnnotationsValidationRunner.GetErrors(item);
if (errors.Count() > 0)
{
throw new RulesException(errors);
}
_server.Database.GetCollection<T>().Save(item);
}
public void Delete<T>(System.Linq.Expressions.Expression<Func<T, bool>> expression) where T : class
{
var items = All<T>().Where(expression);
foreach (T item in items)
{
Delete(item);
}
}
public void Delete<T>(T item) where T : class
{
_server.GetCollection<T>().Delete(item);
}
public void Drop<T>() where T : class
{
_server.Database.DropCollection(typeof(T).Name);
}
public void Dispose() {
_server.Dispose();
}
}
And now my MongoRepositoryBase
public abstract class MongoRepositoryBase<T> : ISession<T> where T : MongoObject
{
protected ISession _session;
protected MongoRepositoryBase(ISession session)
{
_session = session;
}
public T Single(ObjectId id)
{
return _session.All<T>().Where(x => x.Id == id).FirstOrDefault();
}
public T Single(Expression<Func<T, bool>> expression)
{
return _session.Single(expression);
}
public IQueryable<T> All()
{
return _session.All<T>();
}
public void Save(IEnumerable<T> items)
{
foreach (T item in items)
{
Save(item);
}
}
public void Save(T item)
{
_session.Save(item);
}
public void Delete(System.Linq.Expressions.Expression<Func<T, bool>> expression)
{
var items = _session.All<T>().Where(expression);
foreach (T item in items)
{
Delete(item);
}
}
public void DeleteAll()
{
var items = _session.All<T>();
foreach (T item in items)
{
Delete(item);
}
}
public void Delete(T item)
{
_session.Delete(item);
}
public void Drop()
{
_session.Drop<T>();
}
public void Dispose()
{
_session.Dispose();
}
}
And an exemple of an other Repository implemantation :
public class PlaceRepository : MongoRepositoryBase<Place>, IPlaceRepository
{
public PlaceRepository(ISession session) : base(session)
{
}
public List<Place> GetByCategory(PlaceCategory category, bool publishedOnly)
{
var query = _session.All<Place>()
.OrderBy(x => x.Name)
.Where(x => x.Category == category);
if (publishedOnly) query = query.Where(x => x.Published);
if (publishedOnly) query = query.Where(x => x.ShowOnMap);
return query.ToList();
}
public Place FindByName(string name)
{
var query = _session.All<Place>()
.Where(x => x.Name.ToLower().Contains(name.ToLower()))
.Where(x => x.Published);
return query.FirstOrDefault();
}
public string[] FindSuggestionsByName(string name)
{
var query = _session.All<Place>()
.OrderBy(x => x.Name)
.Where(x => x.Name.ToLower().StartsWith(name.ToLower()))
.Where(x => x.Published);
var places = query.ToList();
var names = new string[places.Count];
var i = 0;
foreach (var place in places)
{
names[i++] = place.Name;
}
return names;
}
}
Vinny,
I've never used Ninject, so I could be way off with this suggestion. But it seems possible that having a static MongoSession instance might be holding connections open. Have you tried TransientBehavior instead of SingletonBehavior? Or maybe change your code to call Dispose (or use using) after you convert your ShortcutLinks to a List? All
var shortcutLionks = _session.All<ShortcutLinks>().ToList();
_session.Dispose();
A better approach might be to use some sort of repository or DAO where the session details are hidden from the controller. I have a RepositoryBase sample at http://www.codevoyeur.com/Articles/20/A-NoRM-MongoDB-Repository-Base-Class.aspx.
Stuart Harris has a similar, arguably more complete implementation at http://red-badger.com/Blog/post/A-simple-IRepository3cT3e-implementation-for-MongoDB-and-NoRM.aspx
Pooled MongoDB connections are relatively cheap to create, so it's probably best to make sure the data access methods are disposing after your done getting/saving data.
If I add throw new NotImplementedException(); in the Dispose() method of my MongoRepositoryBase class it does not get call so I guess Ninject does not handle this for me, If I had
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
_recipeRepo.Dispose();
base.OnActionExecuted(filterContext);
}
In my controller it does get call. It seems to be fine, thx!

Resources