Your models project should contain only functionality related to data models such as: data models themselves, data context, repositories.
Provided code does a simple thing: gets a model based on its identifier, so this can be included in a Repository. E.g:
public class Repository<T> : IRepository<T>
where T : class, new()
{
// for DI, ITaskEntities can be used and your context implements the interface
private TaskEntities _context;
public Repository(TaskEntities context)
{
this._context = context;
}
public IQueryable<T> All
{
get { return _context.Set<T>().AsQueryable(); }
}
public IQueryable<T> AllNoTracking
{
get { return _context.Set<T>().AsNoTracking(); }
}
public T Get(int id)
{
return _context.Set<T>().Find(id);
}
// works only if guid is marked as Key, otherwise a special method must be used
public T Get(Guid guid)
{
return _context.Set<T>().Find(id);
}
public void Delete(T entity)
{
if (_context.Entry(entity).State == EntityState.Detached)
_context.Set<T>().Attach(entity);
_context.Set<T>().Remove(entity);
}
public void Insert(T entity)
{
_context.Set<T>().Add(entity);
}
public void Update(T entity)
{
_context.Set<T>().Attach(entity);
_context.Entry(entity).State = EntityState.Modified;
}
}
where IRepository
contains definitions for all public methods in the class above, thus allowing the repository to be injected.
So, your service layer should not work directly with EF data context, but rather using the appropriate repository:
// normally, context and repository should be injected using DI
var taskRepo = new Repository<TASK>(context);
var theTask = taskRepo.Get(myUid);
If the guid is not a key, the search can be performed like this:
// use AllNoTracking, if the model may not be tracked (is not changed and the changes persisted)
var theTask = taskRepo.All.Where(t => t.TASK_SYS_GUID.Equals(guid))
A possible approach is to put all the repositories in a UnitOfWork class, so that multiple changes can be done in a single unit of work (transaction). Something like this:
public class UnitOfWork : IUnitOfWork
{
#region Members
private TaskEntities _context;
#endregion
#region Properties
public IRepository<TASK> TaskRepository { get; private set; }
#endregion
#region Constructor
public UnitOfWork(TaskEntities context,
IRepository<TASK> taskRepository)
{
this._context = context;
TaskRepository = taskRepository ;
}
#endregion
#region Methods
public IRepository<T> GetRepository<T>()
where T: class
{
Type thisType = this.GetType();
foreach (var prop in thisType.GetProperties())
{
var propType = prop.PropertyType;
if (!typeof(IRepository).IsAssignableFrom(propType))
continue;
var repoType = propType.GenericTypeArguments[0];
if (repoType == typeof(T))
return (IRepository<T>) prop.GetValue(this);
}
throw new ArgumentException(String.Format("No repository of type {0} found", typeof(T).FullName));
}
public void SaveChanges()
{
_context.SaveChanges();
}
#endregion
}
Other repositories can be added here and, if DI is used you should never instantiate this class yourself, so that all constructor parameters are injected.
So, your flow should be like this:
- instantiate a
UnitOfWork
- fetch and change models as needed
- finally, call
SaveChanges
I would also mention a little about your naming. C# uses a CamelCase notation for most identifiers (class names, public methods etc.), so you should try to use also for your structures:
TASK -> Task
TASK_SYS_GUID -> TaskSysGuid