I have an asp.net mvc application where I use EF CodeFirst with a repository pattern and am trying to test and catch a DbUpdateConcurrencyException, but it doesn't appear to be firing, evening though when I update a record in one browser, while it is already open in another, and then go to the other and try to update the same record, it allows me to do it. I have a TimeStamp column on the table (called RowVersion) which does change with every update, so that is correct, and from watching sql profiler I can see the update statement does check that the timestamp is what is being passed in, so I'm out of ideas, and am unable to find anything so far to really help me. If anyone can see something I am doing wrong, please let me know. Thanks!!
Here is my entity:
public class MyEntity : EntityBase
{
public override int Id { get; set; }
public DateTime? LastEdited { get; set; }
[Timestamp]
public byte[] RowVersion { get; set; }
}
Here is the repository and it's base classes/dbcontext:
public class MyEntityDataProvider : EfDataProviderBase<MyEntity>, IMyEntityDataProvider
{
public MyEntityDataProvider (IDataContext dataContext) : base(dataContext) { }
}
public abstract class EfDataProviderBase<T> : DataProviderBase<T> where T : EntityBase
{
public new DbDataContext DataContext
{
get { return base.DataContext as DbDataContext; }
protected set { base.DataContext = value; }
}
public EfDataProviderBase(IDataContext dataContext)
: base(dataContext)
{
if (!(dataContext is DbDataContext)) throw new ArgumentException("Parameter 'dataContext' must be of type DbDataContext.");
}
public override T GetById(int id)
{
if (id < 1) return null;
return this.DataContext.GetDbSet<T>().Find(id);
}
public override List<T> GetAll()
{
return this.DataContext.GetDbSet<T>().OrderBy(e => e.Id).ToList();
}
public override void Insert(T entity)
{
if (entity == null) throw new ArgumentNullException("entity");
this.DataContext.GetDbSet<T>().Add(entity);
}
public override void Update(T entity)
{
if (entity == null) throw new ArgumentNullException("entity");
if (!this.DataContext.GetDbSet<T>().Local.Any(e => e.Id == entity.Id))
this.DataContext.GetDbSet<T>().Attach(entity);
this.DataContext.Entry(entity).State = EntityState.Modified;
}
}
public class DbDataContext : DbContext, IDataContext
{
public DbSet<MyEntity> MyEntities { get; set; }
public DbSet<T> GetDbSet<T>() where T : EntityBase
{
Type entityType = typeof(T);
if (entityType == typeof(User))
return this.Users as DbSet<T>;
}
public void Commit()
{
this.SaveChanges();
}
}
public abstract class DataProviderBase<T> : IDataProvider<T> where T: EntityBase
{
public IDataContext DataContext { get; protected set; }
public DataProviderBase(IDataContext dataContext)
{
if (dataContext == null) throw new ArgumentNullException("dataContext");
this.DataContext = dataContext;
}
public abstract T GetById(int id);
public abstract List<T> GetAll();
public void Save(T entity)
{
if (entity == null) throw new ArgumentNullException("entity");
if (entity.IsNew)
{
this.Insert(entity);
}
else if (entity.IsDeleted)
{
this.Delete(entity);
}
else
{
this.Update(entity);
}
}
public abstract void Insert(T entity);
public abstract void Update(T entity);
}
Here is my controller action:
[HttpPost]
[ValidateAntiForgeryToken()]
public ActionResult UpdateViewModel(ViewModel model)
{
if (ModelState.IsValid)
{
try
{
MyEntity current = this.MyEntityDataProvider.GetById(model.Id);
current.LastEdited = DateTime.UtcNow;
current.RowVersion = model.Timestamp; // should have original timestamp, getting from hidden field on view
this.MyEntityDataProvider.Save(current);
this.DataContext.Commit(); // one dbcontext per http request, injected by ninject
return Json(new { success = "Saved!" });
}
catch (DbUpdateConcurrencyException)
{
ModelState.AddModelError("", "This record has been edited by an another person since you have opened it - please close and re-open to attempt your changes again.");
}
}
return Json(new { errors = GetErrorsFromModelState() });
}
Good morning friend.
You should add information on the property you want to control concurrency.
Example:
[ConcurrencyCheck]
public int Code {get; set;}
Related
I am developing Web Applications using ASP.Net MVC 5 (.net framework), now trying develop my next Project using .NET Core 3.1 with Entity framework Core (with Code first approach).
I am trying separate business logic in a separate Wrapper class like:
public interface IValidationDictionary
{
void AddError(string key, string errorMessage);
bool IsValid { get; }
}
public class ModelStateWrapper : IValidationDictionary
{
private ModelStateDictionary _modelState;
public ModelStateWrapper(ModelStateDictionary modelState)
{
_modelState = modelState;
}
#region IValidationDictionary Members
public void AddError(string key, string errorMessage)
{
_modelState.AddModelError(key, errorMessage);
}
public bool IsValid
{
get { return _modelState.IsValid; }
}
#endregion
}
In the EmployeeRepo class:
private Models.IValidationDictionary _modelState;
public EmployeeRepo(Models.IValidationDictionary modelState)
{
_modelState = modelState;
}
public int Create(Models.Employee ObjToCreate)
{
if (!Validate(ObjToCreate))
return 0;
_context.Employee.Add(ObjToCreate);
_context.SaveChanges();
return ObjToCreate.Id;
}
protected bool Validate(Models.Employee objToValidate)
{
if (objToValidate.Name.Trim().Length == 0)
_modelState.AddError("Name", "Name is required.");
if (null == objToValidate.DOB)
_modelState.AddError("DOB", "DOB is required");
return _modelState.IsValid;
}
In the Controller:
private Repository.IEmployeeRepo repo;
public EmployeesController(ApplicationDbContext context)
{
_context = context;
repo = new Repository.EmployeeRepo(new Models.ModelStateWrapper(this.ModelState));
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create([Bind("Name,DOB,Department")] Employee employee)
{
var respId = repo.Create(employee);
if (0 != respId.Id)
{
return RedirectToAction(nameof(Details), new { id = respId.Id });
}
return View(employee);
}
I am expecting ModelState errors to be update in the controller which is added by the wrapper class, but model validation error not updating in the Controller.
Thanks for your time and for any response.
With Best Regards,
Raju Mukherjee
You just want to use a custom verification method to verify these two
fields, right?
The method you wrote is too complicated.
To bind the corresponding error message, you need to add your custom verification attribute above the corresponding fields like [Required].
In fact, you only need to inherit the ValidationAttribute method and rewrite the IsValid method.
public class Employee
{
public int Id { get; set; }
[CustomValidate]
public string Name { get; set; }
[CustomValidate]
public string DOB { get; set; }
public string Department{ get; set; }
}
Custom Method:
public class CustomValidateAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value == null || string.IsNullOrEmpty(value.ToString().Trim()))
{
return new ValidationResult(validationContext.DisplayName + " is required.");
}
return ValidationResult.Success;
}
}
Create:
[HttpPost]
public IActionResult Create([Bind("Name,DOB,Department")]Employee employee)
{
if (ModelState.IsValid)
{
_context.Employee.Add(employee);
_context.SaveChanges();
return RedirectToAction(nameof(Details), new { id = employee.Id });
}
return View(employee);
}
Here is the test result:
We are getting ready to modularize a large enterprise application that is currently using a dying stack of technologies. My question is in the Repository/Unit of Work pattern, how many Repositories can you have in a unit of work? Say for example we create a UnitOfWork on a single DbContext that exposes 50+ repository entities. Will this cause performance problems?
We were looking at maybe splitting it up so that each schema has it's own DbContext but this seems to add a lot of complexity and then doesn't allow for easy joining of data between the schemas. I feel like creating everything under one context/unit of work is the best answer for ease of use and maintainability but I am concerned performance may be a problem.
public class UnitOfWork : IUnitOfWork
{
private readonly AppContext _context;
public UnitOfWork(AppContext context)
{
_context = context;
Courses = new CourseRepository(_context);
Authors = new AuthorRepository(_context);
...
...
// Will lots of repositories here cause a performance problem?
...
...
...
...
...
}
public ICourseRepository Courses { get; private set; }
public IAuthorRepository Authors { get; private set; }
...
...
public int Complete()
{
return _context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
}
It's a few years old now but I've used a UnitOfWork with a GenericRepository and not suffered any major performance issues. This is hooked into over 100 DB tables of a busy website.
That said, the website in question also employs the Dapper Micro-ORM throughout as it's very fast and gives more control on complex operations. For CRUD though, the setup below works well for me.
Unit Of Work
public class UnitOfWork :IDisposable
{
private DbContext _db = new DbContext();
private GenericRepository<Table1> table1Repository;
private GenericRepository<Table2> table2Repository;
private GenericRepository<Table3> table3Repository;
...
private GenericRepository<TableN> tableNRepository;
public GenericRepository<Table1> Table1Repository
{
get
{
if (this.table1Repository == null)
{
this.table1Repository = new GenericRepository<Table1>(_db);
}
return table1Repository;
}
}
public void Save()
{
_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);
}
}
Generic Repository
public class GenericRepository<TEntity> where TEntity :class
{
internal DbContext _db;
internal DbSet<TEntity> dbSet;
public GenericRepository(DbContext _db)
{
this._db = _db;
this.dbSet = _db.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);
}
else
{
return query;
}
}
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 (_db.Entry(entityToDelete).State == EntityState.Detached)
{
dbSet.Attach(entityToDelete);
}
dbSet.Remove(entityToDelete);
}
public virtual void Update(TEntity entityToUpdate)
{
dbSet.Attach(entityToUpdate);
_db.Entry(entityToUpdate).State = EntityState.Modified;
}
}
Usage
var unitOfWork = new UnitOfWork();
List<Table1> list = unitOfWork.Table1Repository.Get(n => n.addedOn <= DateTime.Now);
Table1 item = unitOfWork.Table1Repository.GetById(1);
unitOfWork.Table1Repository.Insert(object);
unitOfWork.Save();
unitOfWork.Table1Repository.Update(object);
unitOfWork.Save();
unitOfWork.Table1Repository.Delete(1);
unitOfWork.Save();
unitOfWork.Table1Repository.Delete(object);
unitOfWork.Save();
Please How do I delete all existing records, refresh and reset the table before I Save new records. I want to do it from my controller.
Controller
public ActionResult Create(ITEM items)
{
try
{
// TODO: Add insert logic here
if (ModelState.IsValid)
{
_itemsService.AddCity(thirdparties);
return RedirectToAction("Index");
}
}
catch
{
ModelState.AddModelError("", "We cannot add this items. Verify your data entries !");
}
return View(items);
}
I have an N-Tier layer
Infrastructure
Repository
Web(Presentation
Infrastructure
public interface IRepository<T> where T : class
{
IEnumerable<T> FindAll(Expression<Func<T, bool>> predicate = null);
T FindById(object id);
T FindByEntity(T entity);
T FindByString(object strValue);
void Add(T entity);
void Remove(T entity);
}
public abstract class Repository<T> : IRepository<T> where T : class
{
public virtual IEnumerable<T> FindAll(Expression<Func<T, bool>> predicate = null)
{
IQueryable<T> items = DataContextFactory.AdminEntities.Set<T>();
return (predicate == null) ? items : items.Where(predicate);
}
public abstract T FindById(object id);
public abstract T FindByString(object strValue);
public abstract T FindByEntity(T entity);
public virtual void Add(T entity)
{
DataContextFactory.AdminEntities.Set<T>().AddOrUpdate(entity);
DataContextFactory.AdminEntities.SaveChanges();
}
public virtual void Remove(T entity)
{
T item = FindByEntity(entity);
if (item != null)
DataContextFactory.AdminEntities.Set<T>().Remove(item);
DataContextFactory.AdminEntities.SaveChanges();
}
}
Repository
public class CitiesManager: ICitiesManager
{
private readonly IRepository<CITIES> _citiesRepository;
public CitiesManager(IRepository<CITIES> citiesRepository)
{
_citiesRepository = citiesRepository;
}
public CITIES City(Int32 cityID)
{
return _citiesRepository.FindById(cityID);
}
public IEnumerable<CITIES> Cities()
{
return _citiesRepository.FindAll().ToList();
}
public void AddCity(CITIES cities)
{
_citiesRepository.Add(cities);
}
public void RemoveCity(Int32 cityID)
{
_citiesRepository.Remove(City(cityID));
}
}
My model classes are in the infrastucture
Infrastructure --> Repository --> Web
I am having a hard time figuring this out. I have implemented Repository and Unit of Work patterns as a data access abstraction for my database. I am using Dependency Injection to inject them into the controller. The problem is when the controller is disposed, it disposes the repository, but then when I refresh the page, DbContext object inside repository is null (it shouldn't be, I think). The implementation of classes is shown below.
This is the database Repository class:
public class ConferenceCrawlyDbRepository : IConferenceCrawlyDbRepository
{
private ConferenceCrawlyDbContext _context = null;
private static ConferenceCrawlyDbRepository _instance = null;
public IRepository<AcademicDegree> AcademicDegrees { get; private set; }
public IRepository<Conference> Conferences { get; private set; }
public IRepository<ConferenceComment> ConferenceComments { get; private set; }
public IRepository<ConferenceRating> ConferenceRatings { get; private set; }
public IRepository<ConnectionConferenceRecommendation> ConnectionConferenceRecommendation { get; private set; }
public IRepository<Country> Countries { get; private set; }
public IRepository<ImportantDate> ImportantDates { get; private set; }
public IRepository<Topic> Topics { get; private set; }
public IRepository<UserProfile> UserProfiles { get; private set; }
public IRepository<UserProfileSettings> UserProfileSettings { get; private set; }
public IRepository<UsersConnection> UserConnections { get; private set; }
public IRepository<Venue> Venues { get; private set; }
private ConferenceCrawlyDbRepository(ConferenceCrawlyDbContext context)
{
_context = context;
AcademicDegrees = new Repository<AcademicDegree>(context);
Conferences = new Repository<Conference>(context);
ConferenceComments = new Repository<ConferenceComment>(context);
ConferenceRatings = new Repository<ConferenceRating>(context);
ConnectionConferenceRecommendation = new Repository<ConnectionConferenceRecommendation>(context);
Countries = new Repository<Country>(context);
ImportantDates = new Repository<ImportantDate>(context);
Topics = new Repository<Topic>(context);
UserProfiles = new Repository<UserProfile>(context);
UserProfileSettings = new Repository<UserProfileSettings>(context);
UserConnections = new Repository<UsersConnection>(context);
Venues = new Repository<Venue>(context);
}
public static ConferenceCrawlyDbRepository Instance
{
get
{
if (_instance == null)
_instance = new ConferenceCrawlyDbRepository(new ConferenceCrawlyDbContext());
return _instance;
}
}
public bool CommitChanges()
{
try
{
return _context.SaveChanges() > 0;
}
catch
{
// TODO: Add logging
return false;
}
}
public void Dispose()
{
if (_context != null)
_context.Dispose();
}
And this is the generic repository class:
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
private ConferenceCrawlyDbContext _context = null;
private DbSet<TEntity> _dbSet = null;
public Repository(ConferenceCrawlyDbContext context)
{
_context = context;
_dbSet = context.Set<TEntity>();
}
public DbSet<TEntity> DbSet
{
get
{
return _dbSet;
}
}
public bool Add(TEntity entity)
{
try
{
DbSet.Add(entity);
return true;
}
catch (Exception ex)
{
// TODO: Add logging
return false;
}
}
public bool Update(TEntity entity)
{
try
{
var entry = _context.Entry<TEntity>(entity);
DbSet.Attach(entity);
entry.State = EntityState.Modified;
return true;
}
catch(Exception ex)
{
// TODO: Add logging
return false;
}
}
public bool Remove(TEntity entity)
{
try
{
DbSet.Remove(entity);
return true;
}
catch (Exception ex)
{
// TODO: Add logging
return false;
}
}
public IQueryable<TEntity> GetAll()
{
return DbSet;
}
public IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.Where(predicate);
}
public TEntity FindById(params object[] keys)
{
return DbSet.Find(keys);
}
public bool Contains(Expression<Func<TEntity, bool>> predicate)
{
return _dbSet.Any(predicate);
}
public bool CommitChanges()
{
try
{
return _context.SaveChanges() > 0;
}
catch
{
// TODO: Add logging
return false;
}
}
public void Dispose()
{
if (_context != null)
_context.Dispose();
}
}
Here is my custom controller factory for dependency injection:
public class CustomControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType != null)
{
if (controllerType.GetConstructor(new Type[] { typeof(IConferenceCrawlyDbRepository) }) != null)
return Activator.CreateInstance(controllerType, new object[] { ConferenceCrawlyDbRepository.Instance }) as Controller;
else if (controllerType.GetConstructor(new Type[] { typeof(IConferenceCrawlyDbRepository), typeof(IMailService) }) != null)
return Activator.CreateInstance(controllerType, new object[] { ConferenceCrawlyDbRepository.Instance,
#if DEBUG
MockMailService.Instance
#else
MailService.Instance
#endif
}) as Controller;
}
return base.GetControllerInstance(requestContext, controllerType);
}
And finally, controller with its action:
public class HomeController : Controller
{
private IConferenceCrawlyDbRepository _dbRepository;
private IMailService _mailService;
public HomeController(IConferenceCrawlyDbRepository dbRepository, IMailService mailService)
{
_dbRepository = dbRepository;
_mailService = mailService;
}
//
// GET: /
public ActionResult Index()
{
var countries = _dbRepository.Countries.GetAll().ToList();
return View(countries);
}
//
// GET: /Home/About
public ActionResult About()
{
return View();
}
//
// GET: /Home/Contact
public ActionResult Contact()
{
return View(new Contact());
}
//
// POST: /Home/Contact
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Contact(Contact contact)
{
if (ModelState.IsValid)
{
if (await _mailService.SendMail(contact.Email, contact.Title,
String.Format("{1}{0}{2}", Environment.NewLine, contact.Message, String.IsNullOrEmpty(contact.Name) ? "Anonimous" : contact.Name)))
{
ViewBag.SuccessMessage = "Comment has been successfully sent.";
return View(new Contact());
}
else
ViewBag.ErrorMessage = "Couldn't send your email. Please try again later";
}
return View(contact);
}
protected override void Dispose(bool disposing)
{
if (_dbRepository != null)
_dbRepository.Dispose();
base.Dispose(disposing);
}
}
The Exception is thrown inside index action when I call the repository, but only after the first time accessing this controller and it says that DbContext object inside repository. I am obviously doing something wrong, but I can't figure it out.
I figure it out after long staring and debugging of code. It's so simple, because I'm disposing context inside ConferenceCrawlyDbRepository I should also set _instance object which is using it to null, and then it will be recreated along with DbContext object. I fell so stupid right now...
I'm developing a web application in ASP.NET MVC with NHibernate.
Based in articles and tutorials I've found at Google, I'm using Repository for my classes.
I have 10 classes and 10 repositories. Today I figured out that 90% of mine repositories are exactly equal each other, except for the class. This is one example:
public class PromocaoRepository:IPromocaoRepository {
private ISession Session;
public PromocaoRepository() {
this.Session = NHibernateSessionFactory.OpenSession();
}
public void Add(Promocao promocao) {
using(ITransaction transaction = this.Session.BeginTransaction()) {
this.Session.Save(promocao);
transaction.Commit();
}
}
public void Edit(Promocao promocao) {
using(ITransaction transaction = this.Session.BeginTransaction()) {
this.Session.Update(promocao);
transaction.Commit();
}
}
public void Remove(Promocao promocao) {
using(ITransaction transaction = this.Session.BeginTransaction()) {
this.Session.Delete(promocao);
transaction.Commit();
}
}
public Promocao GetById(int id) {
return this.Session.Get<Promocao>(id);
}
}
There is a way to do a kind of generic repository witch I can use in all my classes?
If it's possible, what should I do in case I need to create a particular method for an specific class?
From another thread:
public interface IRepository<T> : IQueryable<T>
{
void Add(T entity);
T Get(Guid id);
void Remove(T entity);
}
public class Repository<T> : IQueryable<T>
{
private readonly ISession session;
public Repository(ISession session)
{
session = session;
}
public Type ElementType
{
get { return session.Query<T>().ElementType; }
}
public Expression Expression
{
get { return session.Query<T>().Expression; }
}
public IQueryProvider Provider
{
get { return session.Query<T>().Provider; }
}
public void Add(T entity)
{
session.Save(entity);
}
public T Get(Guid id)
{
return session.Get<T>(id);
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return session.Query<T>().GetEnumerator();
}
public void Remove(T entity)
{
session.Delete(entity);
}
}
Wrapping up nHibernate in repositories
That being said, you should take a look at S#arp Architecture, which already helps you with this repetitive process using Dependency Injection.
You should make a generic repository, which you can use in the general case, and if any extra methods is needed for a particular class, add it by using inheritance. Using your example:
public class GenericRepository<TEntity> :IGenericRepository<TEntity> {
private ISession Session;
public GenericRepository() {
this.Session = NHibernateSessionFactory.OpenSession();
}
public void Add(TEntity instance) {
using(ITransaction transaction = this.Session.BeginTransaction()) {
this.Session.Save(instance);
transaction.Commit();
}
}
/* other methods */
}
public class SpecificRepository : GenericRepository<SpecificEntity>, ISpecificRepository
{
public void SpecialQuery() { /* added method implementation */ }
}
Here is my answer to a similar question (28 votes as of right now):
Advantage of creating a generic repository vs. specific repository for each object?
The idea is to genericize the implementation, not the interface. Instead of an outward-facing generic repository interface, create an inward-facing generic repository base class, which you use to easily implement entity-specific interfaces.
Edit: I should point out that generic repositories serve a very different function than specific repositories. Repositories are intended to encapsulate the data access mechanisms behind the entity's queries, including all of the query logic. A generic repository encapsulates the ability to create queries, but it doesn't encapsulate any specific query about an entity.
The point is to not make repository consumers responsible for writing their own queries. A generic repository lives at the same level of abstraction as an ORM; a specific repository lives at a level above that.
Here's another example of a generic repository
Have a look at my answer to the question "Asp.net MVC 2 Entity Framework Generic Repository Method. how to Update a specific Collumn" - it should give you a good idea of what to do.
HTHs,
Charles
E.g.
Base model:
public interface IDbTable
{
int Id { get; set; }
DateTime DateCreated { get; set; }
DateTime DateUpdated { get; set; }
}
public class DbTable
{
public int Id { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateUpdated { get; set; }
}
Your model
public class Category : DbTable
{
public string Name { get; set; }
}
Your repository
public interface IBaseRepository<T> where T : class, IDbTable
{
void Add<T>(T entity);
void Edit<T>(T entity);
void Remove<T>(T entity);
T GetById(int id);
}
public class BaseRepository<T> : IBaseRepository<T>
{
private ISession Session;
public BaseRepository()
{
this.Session = NHibernateSessionFactory.OpenSession();
}
public void Add(T entity)
{
entity.DateCreated = DateTime.UtcNow;
entity.DateUpdated = DateTime.UtcNow;
using(ITransaction transaction = this.Session.BeginTransaction())
{
this.Session.Save(entity);
transaction.Commit();
}
}
public void Edit(T entity)
{
entity.DateUpdated = DateTime.UtcNow;
using(ITransaction transaction = this.Session.BeginTransaction())
{
this.Session.Update(entity);
transaction.Commit();
}
}
public void Remove(T entity)
{
using(ITransaction transaction = this.Session.BeginTransaction())
{
this.Session.Delete(entity);
transaction.Commit();
}
}
public T GetById(int id)
{
return this.Session.Get<T>(id);
}
}
Oh, and lets not forget the concrete implementation
public interface ICategoryRepository : IBaseRepository<Category>
{
Category GetCategoryByName(string categoryName);
}
public CategoryRepository : BaseRepository<Category>
{
public Category GetCategoryByName(string categoryName)
{
//blah
}
}