I'm looking for your opinions about ways to improve the access to data in my application. I develop web applications, using Entity Framework 6 code first, and Autofac for dependency injection.
Before you dive in the code, keep in mind that all components in my application (except for the problematic RepositoriesFactory
you will see below) are registered by the IoC container. My root (Startapp) registers all components, using a .dll I developed that supplies API for DI (Autofac wrapper), that's because I don't want Autofac references in my web project. Furthermore, I want this .dll I developed to be known and used only in my root because I know this is the best practice.
My data management:
public abstract class BaseEntityObject
{
[Key]
public int DbIndex {get; set;}
}
public class Letter : BaseEntityObject
{
[DataMember]
public int Id {get; set;}
[DataMember]
public string Title {get; set;}
[DataMember]
public string Content {get; set;}
public virtual Folder Folder {get; set;}
[DataMember]
public int FolderId {get; set;}
[DataMember]
public DateTime CreationDate {get; set;}
}
public class Folder : BaseEntityObject
{
[DataMember]
public int Id {get; set;}
[DataMember]
public string Name {get; set;}
[DataMember]
public List<Letter> Letters {get; set;}
}
public IRepository<T> where T: BaseEntityObject
{
void Add(T entity);
void Remove(T entity);
List<T> Get();
T FindById(int id);
int SaveChanges();
void Dispose();
}
public abstract class EFRepository<T> : IRepository<T>
{
protected readonly DbContext Context;
public EFRepository(DbContext context)
{
Context = context;
}
public abstract List<T> Get();
public void Add(T item)
{
Context.Set<T>().Add(item);
}
public void Remove(T item)
{
Context.Set<T>().Remove(item);
}
public void Update(T item)
{
Context.Entry(item).State = EntityState.Modified;
}
public void Dispose()
{
Context.Dispose();
}
public int SaveChanges()
{
return Context.SaveChanges();
}
public T FindById(int id)
{
return Context.Set<T>().Find(id);
}
}
public LettersRepository : EFRepository<Letter>
{
public LettersRepository(DbContext context) : base(context) {}
// Override for case includes will be needed in future
public override List<T> Get()
{
return Context.Set<T>().ToList();
}
}
public FoldersRepository : EFRepository<Folder>
{
public FoldersRepository(DbContext context) : base(context) {}
public override List<T> Get()
{
return Context.Set<T>().Include("Letters").ToList();
}
}
public class DataService
{
private IRepositoriesFactory _factory
public DataService(IRepositoriesFactory repoFactory)
{
_factory = repoFactory;
}
public void AddFolder(Folder folder)
{
using (var foldersRepository = _factory.Create<FoldersRepository>())
{
try
{
foldersRepository.Add(folder)
foldersRepository.SaveChanges();
}
catch(Exception)
{
Log ("AddFolder failed");
}
}
}
public void AddLetter(Letter letter)
{
using (var lettersRepository = _factory.Create<LettersRepository>())
{
try
{
foldersRepository.Add(letter)
foldersRepository.SaveChanges();
}
catch(Exception)
{
Log ("AddLetter failed");
}
}
}
public void RemoveFolder(int id)
{
using (var foldersRepository = _factory.Create<FoldersRepository>())
{
try
{
var folder = foldersRepository.FindById(id);
foldersRepository.Remove(folder)
foldersRepository.SaveChanges();
}
catch(Exception)
{
Log ("RemoveFolder failed");
}
}
}
public void RemoveLetter(int id)
{
using (var lettersRepository = _factory.Create<LettersRepository>())
{
try
{
var letter = lettersRepository.FindById(id);
lettersRepository.Remove(letter);
lettersRepository.SaveChanges();
}
catch(Exception)
{
Log ("RemoveLetter failed");
}
}
}
public bool ChangeLetterFolder(int letterId, int destinationFolder)
{
using (var lettersRepository = _factory.Create<LettersRepository>())
{
try
{
var letter = lettersRepository.FindById(letterId);
letter.FolderId = destinationFolder;
lettersRepository.Update(letter);
lettersRepository.SaveChanges();
}
catch(Exception)
{
Log (string.Format("Changing letter {0} folder failed", letterId));
}
}
}
public List<Letter> GetLettersAfterSpecificDate(DateTime date)
{
using (var lettersRepository = _factory.Create<LettersRepository>())
{
try
{
return lettersRepository.Get().Where(x => x.CreationDate < date).ToList();
}
catch(Exception)
{
Log (string.Format("Getting all letters before : {0} failed", date));
}
}
}
}
public interface IApplicationDbContext
{
DbSet<Folder> Folders {get; set;}
DbSet<Letter> Letters {get; set;}
}
public ApplicationDbContext : DbContext, IApplicationDbContext
{
public DbSet<Folder> Folders {get; set;}
public DbSet<Letter> Letters {get; set;}
public ApplicationDbContext () : base("name=Application.DbConntection")
{
Database.SetInitializer(new CreateDatabaseIfNotExists<ApplicationDbContext>());
}
}
public interface IRepositoriesFactory
{
IRepository<BaseEntityObject> Create<T>();
}
// I truely hate this piece of code,
// but don't know how to use dependceny injection without having a mess with
// my references in order to register this factory
public class RepositoriesFactory : IRepositoriesFactory
{
public IRepository<BaseEntityObject> Create<T>()
{
if (typeof(T) == typeof(FoldersRepository))
return new FoldersRepository(new ApplicationDbContext());
if (typeof(T) == typeof(LettersRepository))
return new LettersRepository(new ApplicationDbContext());
return null;
}
}