问题
I have implemented EntityFramework pattern along with Repository and Unit Of Work. The implementation is similar to Code Project Repository Example, however I need an enhancement for the Unit Of Work.
The unit of work
public class GenericUnitOfWork : IDisposable
{
// Initialization code
public Dictionary<Type, object> repositories = new Dictionary<Type, object>();
public IRepository<T> Repository<T>() where T : class
{
if (repositories.Keys.Contains(typeof(T)) == true)
{
return repositories[typeof(T)] as IRepository<T>
}
IRepository<T> repo = new Repository<T>(entities);
repositories.Add(typeof(T), repo);
return repo;
}
// other methods
}
The above UoW is quiet generalized and it targets the parent Repository class always. I have another entity, for example student, which has its own repository extending the Repository class. The student specific repository has a method "GetStudentMarks()". Now I cannot use the general Unit Of Work class since it always points to the parent Repository.
How to implement a general Unit Of Work to handle such situations? Thanks in advance.
回答1:
You can make the class GenericUnitOfWork
generics, specifying the entity and repository type:
public class GenericUnitOfWork<TRepo, TEntity> : IDisposable
where TRepo : Repository<TEntity>
{
// Initialization code
public Dictionary<Type, TRepo> repositories = new Dictionary<Type, TRepo>();
public TRepo Repository()
{
if (repositories.Keys.Contains(typeof(TEntity)) == true)
{
return repositories[typeof(TEntity)];
}
TRepo repo = (TRepo)Activator.CreateInstance(
typeof(TRepo),
new object[] { /*put there parameters to pass*/ });
repositories.Add(typeof(TEntity), repo);
return repo;
}
// other methods
}
Something like this should works.
回答2:
Generic UnitOfWork !!! You've implemented the wrong unit of work
See This Code:
using System.Data.Entity;
using System;
namespace EF_Sample07.DataLayer.Context
{
public interface IUnitOfWork
{
IDbSet<TEntity> Set<TEntity>() where TEntity : class;
int SaveChanges();
}
}
Why Use UnitOfWork?
Because:
- Better performance
- Concurrency issues
- The correct use of transactions
See Example :
Category
public class Category
{
public int Id { get; set; }
public virtual string Name { get; set; }
public virtual string Title { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
Product
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
[ForeignKey("CategoryId")]
public virtual Category Category { get; set; }
public int CategoryId { get; set; }
}
UnitOfWork
public interface IUnitOfWork
{
IDbSet<TEntity> Set<TEntity>() where TEntity : class;
int SaveChanges();
}
DbContext
public class Sample07Context : DbContext, IUnitOfWork
{
public DbSet<Category> Categories { set; get; }
public DbSet<Product> Products { set; get; }
#region IUnitOfWork Members
public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}
public int SaveAllChanges()
{
return base.SaveChanges();
}
#endregion
}
回答3:
I suppose that, you want to perform some operations over StudentMarks in GetStudentMarks
method. Otherwise if your models are correctly mapped, you can just load them using one of the relation data loading methods.
Otherwise, if general Repository suits most of your entities, but you need some additional methods for a little number of your entities, then I recommend creating extension methods for these repositories:
public static class StudentReposityExtensions
{
public List<Mark> GetStudentMarks(
this IRepository<Student> studentRepostitory)
{
.....
}
}
来源:https://stackoverflow.com/questions/39343750/generic-unit-of-work