I'm trying to create a simple data access class which acts as a library to return various entities. All my entity classes are generated via the Linq-to-SQL mapper in VS 2013, and all of them can be returned from the dataContext via Find(primary id)
I'd like to just define generic Find, Delete, Update etc without having to repeat it for every table/object but I don't want to create a Repository pattern.
How do I create a generic method that works regardless? This is what I have and of course it says T not defined, but I thought we could create generic methods in non-generic classes, so what am I doing wrong?
What I'd like to do is something like
var c = DAL<Customer>.Find(id)
var e = DAL<Employee>.Find(id)
... etc.
The code I attempted to write is
public class DAL
{
private string _key;
private DataContext _context = null;
//private DbSet<T> _table = null;
public DAL(string key)
{
_key = key;
_context = new DataContext();
}
public void Dispose()
{
_context.Dispose();
}
public DbSet<T> Find<T>(int id)
{
var d = _context.Set<T>();
//return d.Find(id);
}
}
I'm kind of lost... I do not want to define
public class DAL<T> where T:class
which ties each DAL to a type
This is the first time I'm venturing into generic nethods so any help appreciated
You can specify a generic method of a class, but you will need to use a constraint:
public class DAL
{
// .... previously written code
public DbSet<T> Find<T>(int id) where T : class
{
return _context.Set<T>();
}
}
You will also have to call it like this:
var dal = new DAL();
var data = dal.Find<Customer>(1);
Also note, that your code has a number of problems, you define a dispose method, but you don't implement the IDisposable interface, you're not actually returning anything from the method, etc..
Note: for all intents and purposes, this is still a repository pattern.
Something like this should work:
public T Find<T>(int id) where T : class
{
return context.Set<T>().Find(id);
}
Related
I want to have a generic method, that converts a few known types, to their equivalent types that is accepted by the database to insert them.
public class MongoDataAccess : IDataAccess
{
public Task InsertAsync<T>(string collectionName, T item)
{
// convert T which should be `Student`, `University` etc
// to `StudentDocument`, 'UniversityDocument` etc
}
}
How can I do this, probably using interfaces to apply restrictions?
In addition to having a "data access facade" IDataAccess, you can implement "entity handler" IDataAccess<T> per each entity type (Student, University, etc). Application code will "talk" to the DAL facade, and the DAL facade will delegate to a concrete entity handler.
The DAL facade can look like this:
public interface IDataAccess<TEntity>
{
// no need for collectionName parameter
// because each concrete entity handler knows its collection name
Task InsertAsync(TEntity entity);
// .... other CRUD methods
}
An implementation of a concrete entity handler can look like this:
public class StudentDataAccess : IDataAccess<Student>
{
// initialized elsewhere in this class
private MongoCollection<StudentDocument> _collection;
public Task InsertAsync(Student entity)
{
var document = ConvertToDocument(entity);
return _collection.InsertOneAsync(document);
}
private StudentDocument ConvertToDocument(Student entity)
{
// perform the conversion here....
}
}
This is how the DAL facade will delegate calls to a concrete entity handler:
public class DataAccess
{
public async Task InsertAsync<T>(T entity)
{
//... obtain an instance of IDataAccess<T>
var enityHandler = GetEntityHandler<T>();
return entityHandler.InsertAsync(entity);
}
private IDataAccess<T> GetEntityHandler<T>()
{
// you can use a DI container library like Autofac
// or just implement your own simpliest service locator like this:
return (IDataAccess<T>)_handlerByEntityType[typeof(T)];
}
// the following simplest service locator can be replaced with a
// full-blown DI container like Autofac
private readonly IReadOnlyDictionary<Type, object> _handlerByEntityType =
new Dictionary<Type, object> {
{ typeof(Student), new StudentDataAccess() },
{ typeof(University), new UniversityDataAccess() },
// ... the rest of your entities
};
}
Use this interface.
IConvertible<TSource, TResult>
{
Task<TResult> Convert(string collectionName);
}
Your datatypes like Student and University must implement from this.
I have a many interfaces each with 2 implementations of it:
public interface Foo{/**/}
public class ModelFoo : Foo {/**/}
public class ViewModelFoo : Foo {/**/}
Now I have a repositoryInterface and 2 Implementations with generic functions in it:
public interface Repository
{
ICollection<TModel> GetAll<TModel>();
}
public class ModelRepository : Repository
{
private IDictionary<Type, Type> typeMapping = new Dictionary<Type, Type>();
private DbContext context;
public ICollection<TModel> GetAll<TModel>()
{
var implType = typeMapping[typeof(TModel)];
var ctxSet = context.Set(implType);
return new EFWrapCollection<TModel>(Enumerable.Cast<object>(ctxSet).ToList());
}
}
The first implementation of the interface will load all Models from the database. The dictionary typemapping is needed for typemapping between the interface type and the concrete type. EFWrapCollection wraps the paramter to TModel type.
In the typemapping there are pairs as follows:
(typeof(Foo), typeof(ModelFoo)),
(typeof(Bar), typeof(ModelBar)),
...
The usage will be as follows:
var rep = new ModelRepository(context);
rep.GetAll<Foo>();
This will return all ModelFoo's from the database with the typeparameter Foo. Now I want to do the following:
public class ViewModelRepository : Repository
{
private IDictionary<Type, Type> typeMapping = new Dictionary<Type, Type>();
private Repository repository;
public ICollection<TModel> GetAll<TModel>()
{
var result = repository.getAll<TModel>();
//now i have the problem that i need a cast
//but I dont know hot to achieve it
}
}
In this repository class there is also a typemapping. This attribute holds all mappings between interface type and viewmodel type:
(typeof(Foo), typeof(ViewModelFoo)),
(typeof(Bar), typeof(ViewModelBar)),
.....
The cast should be a cast to the Viewmodeltype. I know how to cast 2 concrete classes, but here I have the problem, that this repository is generic and I dont know the type in the first place.
EDIT
Why I need the cast (or mapping):
In the database there are only Models of the type Model and I want to cast (or map) the type Model into the type ViewModel.
You are mixing apples and oranges. You shouldn't be tracking types inside of the repository. The repository should be specific to the type it works with.
What you can do instead is create a generic repository and pass it the type it should work with. The context has a generic Set<T> method you can take advantage of:
public class Repository<T>
{
private DbContext context;
public ICollection<T> GetAll()
{
var items = context.Set<T>();
return new EFWrapCollection<T>(items);
}
}
I am not entirely sure why you are using that EFWrapCollection but I guess you have your reasons.
I am guessing by now you have realized it's not a very good idea to pass EF objects around, unless you manage the lifetime of the context appropriately. The type mapping can be handled in many different ways. I suggest you look at AutoMapper. You can create a class that maps objects for you and let AutoMapper do most of the work, then provide custom mappings for those not-so-straight-forward properties:
https://cpratt.co/using-automapper-getting-started/
Here is a quick excerpt from the link, to give you an idea:
public static class AutoMapperConfig
{
public static void RegisterMappings()
{
AutoMapper.Mapper.CreateMap<ModelFoo, ViewModelFoo>()
.ForMember(dest => dest.Author,
opts => opts.MapFrom(src => src.Author.Name));
}
}
By the way, the world will appreciate it if you follow conventions and prefix your interfaces with the letter I (e.g. IRepository). It really makes reading code a lot easier. Good luck!
I'm working on a quite large application. The domain has about 20-30 types, implemented as ORM classes (for example EF Code First or XPO, doesn't matter for the question). I've read several articles and suggestions about a generic implementation of the repository pattern and combining it with the unit of work pattern, resulting a code something like this:
public interface IRepository<T> {
IQueryable<T> AsQueryable();
IEnumerable<T> GetAll(Expression<Func<T, bool>> filter);
T GetByID(int id);
T Create();
void Save(T);
void Delete(T);
}
public interface IMyUnitOfWork : IDisposable {
void CommitChanges();
void DropChanges();
IRepository<Product> Products { get; }
IRepository<Customer> Customers { get; }
}
Is this pattern suitable for really large applications? Every example has about 2, maximum 3 repositories in the unit of work. As far as I understood the pattern, at the end of the day the number of repository references (lazy initialized in the implementation) equal (or nearly equal) to the number of domain entity classes, so that one can use the unit of work for complex business logic implementation. So for example let's extend the above code like this:
public interface IMyUnitOfWork : IDisposable {
...
IRepository<Customer> Customers { get; }
IRepository<Product> Products { get; }
IRepository<Orders> Orders { get; }
IRepository<ProductCategory> ProductCategories { get; }
IRepository<Tag> Tags { get; }
IRepository<CustomerStatistics> CustomerStatistics { get; }
IRepository<User> Users { get; }
IRepository<UserGroup> UserGroups { get; }
IRepository<Event> Events { get; }
...
}
How many repositories cab be referenced until one thinks about code smell? Or is it totally normal for this pattern? I could probably separate this interface into 2 or 3 different interfaces all implementing IUnitOfWork, but then the usage would be less comfortable.
UPDATE
I've checked a basically nice solution here recommended by #qujck. My problem with the dynamic repository registration and "dictionary based" approach is that I would like to enjoy the direct references to my repositories, because some of the repositories will have special behaviour. So when I write my business code I would like to be able to use it like this for example:
using (var uow = new MyUnitOfWork()) {
var allowedUsers = uow.Users.GetUsersInRolw("myRole");
// ... or
var clothes = uow.Products.GetInCategories("scarf", "hat", "trousers");
}
So here I'm benefiting that I have a strongly typed IRepository and IRepository reference, hence I can use the special methods (implemented as extension methods or by inheriting from the base interface). If I use a dynamic repository registration and retrieval method, I think I'm gonna loose this, or at least have to do some ugly castings all the time.
For the matter of DI, I would try to inject a repository factory to my real unit of work, so it can lazily instantiate the repositories.
Building on my comments above and on top of the answer here.
With a slightly modified unit of work abstraction
public interface IMyUnitOfWork
{
void CommitChanges();
void DropChanges();
IRepository<T> Repository<T>();
}
You can expose named repositories and specific repository methods with extension methods
public static class MyRepositories
{
public static IRepository<User> Users(this IMyUnitOfWork uow)
{
return uow.Repository<User>();
}
public static IRepository<Product> Products(this IMyUnitOfWork uow)
{
return uow.Repository<Product>();
}
public static IEnumerable<User> GetUsersInRole(
this IRepository<User> users, string role)
{
return users.AsQueryable().Where(x => true).ToList();
}
public static IEnumerable<Product> GetInCategories(
this IRepository<Product> products, params string[] categories)
{
return products.AsQueryable().Where(x => true).ToList();
}
}
That provide access the data as required
using(var uow = new MyUnitOfWork())
{
var allowedUsers = uow.Users().GetUsersInRole("myRole");
var result = uow.Products().GetInCategories("scarf", "hat", "trousers");
}
The way I tend to approach this is to move the type constraint from the repository class to the methods inside it. That means that instead of this:
public interface IMyUnitOfWork : IDisposable
{
IRepository<Customer> Customers { get; }
IRepository<Product> Products { get; }
IRepository<Orders> Orders { get; }
...
}
I have something like this:
public interface IMyUnitOfWork : IDisposable
{
Get<T>(/* some kind of filter expression in T */);
Add<T>(T);
Update<T>(T);
Delete<T>(/* some kind of filter expression in T */);
...
}
The main benefit of this is that you only need one data access object on your unit of work. The downside is that you don't have type-specific methods like Products.GetInCategories() any more. This can be problematic, so my solution to this is usually one of two things.
Separation of concerns
First, you can rethink where the separation between "data access" and "business logic" lies, so that you have a logic-layer class ProductService that has a method GetInCategory() that can do this:
using (var uow = new MyUnitOfWork())
{
var productsInCategory = GetAll<Product>(p => ["scarf", "hat", "trousers"].Contains(u.Category));
}
Your data access and business logic code is still separate.
Encapsulation of queries
Alternatively, you can implement a specification pattern, so you can have a namespace MyProject.Specifications in which there is a base class Specification<T> that has a filter expression somewhere internally, so that you can pass it to the unit of work object and that UoW can use the filter expression. This lets you have derived specifications, which you can pass around, and now you can write this:
using (var uow = new MyUnitOfWork())
{
var searchCategories = new Specifications.Products.GetInCategories("scarf", "hat", "trousers");
var productsInCategories = GetAll<Product>(searchCategories);
}
If you want a central place to keep commonly-used logic like "get user by role" or "get products in category", then instead of keeping it in your repository (which should be pure data access, strictly speaking) then you could have those extension methods on the objects themselves instead. For example, Product could have a method or an extension method InCategory(string) that returns a Specification<Product> or even just a filter such as Expression<Func<Product, bool>>, allowing you to write the query like this:
using (var uow = new MyUnitOfWork())
{
var productsInCategory = GetAll(Product.InCategories("scarf", "hat", "trousers");
}
(Note that this is still a generic method, but type inference will take care of it for you.)
This keeps all the query logic on the object being queried (or on an extensions class for that object), which still keeps your data and logic code nicely separated by class and by file, whilst allowing you to share it as you have been sharing your IRepository<T> extensions previously.
Example
To give a more specific example, I'm using this pattern with EF. I didn't bother with specifications; I just have service classes in the logic layer that use a single unit of work for each logical operation ("add a new user", "get a category of products", "save changes to a product" etc). The core of it looks like this (implementations omitted for brevity and because they're pretty trivial):
public class EFUnitOfWork: IUnitOfWork
{
private DbContext _db;
public EntityFrameworkSourceAdapter(DbContext context) {...}
public void Add<T>(T item) where T : class, new() {...}
public void AddAll<T>(IEnumerable<T> items) where T : class, new() {...}
public T Get<T>(Expression<Func<T, bool>> filter) where T : class, new() {...}
public IQueryable<T> GetAll<T>(Expression<Func<T, bool>> filter = null) where T : class, new() {...}
public void Update<T>(T item) where T : class, new() {...}
public void Remove<T>(Expression<Func<T, bool>> filter) where T : class, new() {...}
public void Commit() {...}
public void Dispose() {...}
}
Most of those methods use _db.Set<T>() to get the relevant DbSet, and then just query it with LINQ using the provided Expression<Func<T, bool>>.
there is a class
public class Repository <TKey, TEntity>
{
public ICollection<TEntity> Get()
{
using (var session = NHibernateHelper.OpenSession())
{
if (typeof(TEntity).IsAssignableFrom(typeof(IActualizable)))
return session.CreateCriteria(typeof(TEntity)).Add(Restrictions.Lt("ActiveTo", DBService.GetServerTime())).List<TEntity>();
return session.CreateCriteria(typeof(TEntity)).List<TEntity>();
}
}
}
how to create it, knowing only the name of TEntity?
Example:
class Game
{
}
string nameEntity = "Game";
var repository = new Repository< long, ??? >();
There's three parts to this:
getting the Type from the string "Game"
creating the generic instance
doing something useful with it
The first is relatively easy, assuming you know a bit more - for example, that Game is in a particular assembly and namespace. If you know some fixed type in that assembly, you could use:
Type type = typeof(SomeKnownType).Assembly
.GetType("The.Namespace." + nameEntity);
(and check it doesn't return null)
Then we need to create the generic type:
object repo = Activator.CreateInstance(
typeof(Repository<,>).MakeGenericType(new[] {typeof(long), type}));
however, note that this is object. It would be more convenient if there was a non-generic interface or base-class that you could use for Repository<,> - I would put serious though into adding one!
To use that, the easiest approach here will be dynamic:
dynamic dynamicRepo = repo;
IList entities = dynamicRepo.Get();
and use the non-generic IList API. If dynamic isn't an option, you'd have to use reflection.
Alternatively, adding a non-generic API would make this trivial:
interface IRepository {
IList Get();
}
public class Repository <TKey, TEntity> : IRepository {
IList IRepository.Get() {
return Get();
}
// your existing code here
}
then it is just:
var repo = (IRepository)Activator.CreateInstance(
typeof(Repository<,>).MakeGenericType(new[] {typeof(long), type}));
IList entities = repo.Get();
Note: depending on the data, IList might not work - you might need to drop to the non-generic IEnumerable instead.
I have a 'Customer' POCO entity within my Entity Framework 4 project. I want to expose my Customer entities to my upper layers as a generic list rather than an ObjectSet.
I have an IUnitOfWork interface which looks as follows:
public interface IUnitOfWork
{
string Save();
IList<Customer> Customers { get; }
}
Down at my Entity Framework DAL (which implements the above interface) I have the following:
public class EntityContainer : ObjectContext, IUnitOfWork
{
private IObjectSet<Customer> _customers;
public IList<Customer> Customers
{
get
{
if (_customers == null)
{
_customers = CreateObjectSet<Customer>("Customers");
}
return _customers.ToList<Customer>() ;
}
}
}
However the 'CreateObjectSet("Customers")' line doesn't work. Every time I try to add a new 'Customer' nothing happens. Interestingly, if I revert to using an IObjectSet then the code works. For example:
public interface IUnitOfWork
{
string Save();
IObjectSet<Contact> Contacts { get; }
}
public class EntityContainer : ObjectContext, IUnitOfWork
{
private IObjectSet<Customer> _customers;
public IObjectSet<Customer> Customers
{
get
{
if (_customers == null)
{
_customers = CreateObjectSet<Customer>("Customers");
}
return _customers;
}
}
}
IQueryable also works, but I cannot get IList to work and I have no idea why. Anyone any ideas?
#
A correction to the original question. Using IQueryable doesn't work, nor does IEnumerable. This is because the Customer repository needs to provide 'Add' and 'Delete' methods to add/delete from the entity collection (add or remove customer entities in the above example). Neither IQueryable or IEnumerable allow you to add or remove objects; instead, an ICollection or IList must be used. This leaves me back at my original problem. I do not want to expose my collection to the repository as an ObjectSet. I want to use a type which is not tied to the EntityFramework i.e. - I want to use a generic list.
Has anyone any more suggestions? I suspect there's a straightforward way of doing this, but I'm not familiar enough with the framework to figure it out.
You seem to be missing a Repository in all of this. The Repository is usually what handles the conversion from ObjectSet<T> to IList<T> (or, in most cases, IEnumerable<T> or IQueryable<T>).
public class EntityContainer : ObjectContext
{
private IObjectSet<Customer> _customers;
public IObjectSet<Customer> Customers
{
get
{
return _customers ??
( _customers = CreateObjectSet<Customer>("Customers");
}
}
}
public class CustomerRepository
{
EntityContext _context = new EntityContext();
public IQueryable<Customer> FindAll()
{
return _context.Customers;
}
public Customer FindById(int id)
{
return _context.Customers.Single(c => c.Id == id);
}
// And so on.
}
I usually then have my UnitOfWork create the Repositories that should be enlisted in the Unit of Work so that anything done through the repositories is bundled in a single operation.
Keep in mind, that my UnitOfWork only would have two methods. One for getting a repository and another for committing the Unit of Work. All data retrieval is handled by the Repositories.
_customers.ToList() is the culprit. ToList executes the query and copies all the items from that query into a new collection object. this new collection object does not provide the tracking capabilities that ObjectSet has.