I have an interface to define my records\models
public interface IStockItem
{
string Code { get; set; }
string Description { get; set; }
decimal FreeStock { get; set; }
}
Is it best to put the actions into another interface?
public interface IStockExport
{
IEnumerable<IStockItem> GetAll();
IEnumerable<IStockItem> GetStockByCode(string code);
decimal GetFreeStock(string code);
}
public interface IStockImport
{
void CreateItem<IStockItem>;
}
Is there a better way to do this and make it more generic? so i can share the actions interfaces with other records\models?
The other records\models are SalesOrder, Customer, Address.
The overall idea is an Import\Export program, that will create\export sales orders in a number of different accounts packages via an API.
This is a common pattern, called the Repository Pattern.
If you want to go down this route, you should create a base interface, Repository<T>, for example:
public interface IRepository<T>
{
void Insert(T entity);
void Delete(T entity);
IEnumerable<T> SearchFor(Func<T, bool> predicate);
IEnumerable<T> GetAll();
T GetById(int id);
}
You would make your IStockItem implement an IEntity interface so that it can provide an ID for GetById(), for example:
public interface IEntity
{
int ID { get; }
}
Then you would implement the repository for a data type such as StockItem by declaring the implementing class. It might start a bit like this:
public class Repository<T> : IRepository<T> where T : class, IEntity
{
protected Table<T> DataTable;
public Repository(DataContext dataContext)
{
DataTable = dataContext.GetTable<T>();
}
...
Your code that wanted to get at a repository for a stock item might look like this:
using (var dataContext = new StockItemDataContext())
{
var StockItemRepository = new Repository<IStockItem>(dataContext);
...
This may be overkill for what you want, but it is the general approach.
For full details see this excellent blog post.
Also see this example.
Here's how you might start implementing this pattern for your case:
public interface IRepository<T>
{
void Insert(T entity);
void Delete(T entity);
IEnumerable<T> SearchFor(Func<T, bool> predicate);
IEnumerable<T> GetAll();
T GetByCode(string code);
}
public interface IStockItem: IEntity
{
string Description { get; set; }
decimal FreeStock { get; set; }
}
public sealed class StockItem: IStockItem
{
public string Code { get; set; }
public string Description { get; set; }
public decimal FreeStock { get; set; }
}
public interface IEntity
{
string Code { get; }
}
public sealed class MyLowLevelDataAccess
{
public StockItem FindStockItem(string code)
{
return null; // Call your API here.
}
public void DeleteStockItem(string code)
{
// Call your API here.
}
public void InsertStockItem(StockItem item)
{
// Call your API here.
}
public IEnumerable<StockItem> FindAllItems()
{
return FindItemsMatching(x => true);
}
public IEnumerable<StockItem> FindItemsMatching(Func<StockItem, bool> predicate)
{
return null; // Call your API here and return all items matching the predicate.
}
}
public sealed class StockRepository: IRepository<StockItem>
{
private readonly MyLowLevelDataAccess _dataAccess;
public StockRepository(MyLowLevelDataAccess dataAccess)
{
_dataAccess = dataAccess;
}
public void Insert(StockItem entity)
{
_dataAccess.InsertStockItem(entity);
}
public void Delete(StockItem entity)
{
_dataAccess.DeleteStockItem(entity.Code);
}
public IEnumerable<StockItem> SearchFor(Func<StockItem, bool> predicate)
{
return _dataAccess.FindItemsMatching(predicate);
}
public IEnumerable<StockItem> GetAll()
{
return _dataAccess.FindAllItems();
}
public StockItem GetByCode(string code)
{
return _dataAccess.FindStockItem(code);
}
}
you can use a generic interface as well:
public interface IRecordExport<T> where T : IRecordBase
{
IEnumerable<T> GetAll();
IEnumerable<T> GetOneByCode(string code);
decimal GetFree(string code);
}
public interface IRecordImport<T> where T : IRecordBase
{
void CreateItem<T>();
}
You could, but it may not be necessary. Interfaces for method-based classes are best used where you want to have polymorphism related to implementation.
In your case, it seems that what you want is to be able to share common functionality (based on the IStockExport interface) but also provide a polymorphic creation mechanism (based on IStockImport).
I would suggest that you implement an abstract base class for IStockExport which can be inherited for all the various types of IStockItem (due to common interface) and then the derived classes should implement IStockExport as each Create<IStockItem>() implementation will be different but can be used in the same way due to common behaviour (always returns IStockItem object).
Related
I've an already existing SQL database that has table Car for example that looks like this
public class Car
{
public string Brand { get; set; }
public string AvailableColorsCommaSperated { get; set; }
}
Now I'm working on migrating to MongoDb so that the data could look like that
public class Car
{
public string Brand { get; set; }
public List<string> Colors { get; set; }
}
But I've to maintain the SQL database at the same time as it will remain used for sometime even after migration.
Now in my DAL layer I had a Master interface and class that looks like Repository pattern which the interface was like that
public interface ICarDAL
{
List<Car> GetAllCars();
}
public class CarDAL : ICarDAL
{
private readonly ICarSQL carSQL;
public CarDAL(ICarSQL carSQL)
{
this.carSQL = carSQL;
}
public List<Car> GetAllCars()
{
return carSQL.GetAllCars();
}
}
While to implement that using the SQLContext another interface and class with implementation exists as so
public interface ICarSQL : ICarDAL
{
new List<Car> GetAllCars();
}
public class CarSQL : ICarSQL
{
private readonly DbContext dbContext;
public CarSQL(DbContext dbContext)
{
this.dbContext = dbContext;
}
public List<Car> GetAllCars()
{
// Get Cars..
}
}
I could have no problem of adding a seperate layer for the Mongo to inherit from the ICarDAL and implement the functions on its own, but the problem is that I will have different Car Model for each one of them (the Car is just an example)
How can I abstract the DAL layer so that I can make the CRUD operations with different Models to different Databases? and am I going to need different context or use the same one with a factory to distinguish between different databases classes?
you can make your interface more generic
public interface IGenericRepository<T> where T : class
{
IEnumerable<T> GetAll();
T GetById(object id);
void Insert(T obj);
void Update(T obj);
void Delete(object id);
void Save();
}
so each dal layer will implement it's own version
you can even use a different type for an ID
for example:
public interface IGenericRepository<T,K> where T : class
{
IEnumerable<T> GetAll();
T GetById(K id);
void Insert(T obj);
void Update(T obj);
void Delete(K id);
void Save();
}
Given classes and interfaces below, I am wondering why implicit cast:
ISomeModelAbstract<IBasicModel> x = new ConcreteClass();
Is impossible. I tried
public interface ISomeModelAbstract<out T> where T: IBasicModel
But then I cannot use GetById and GetAll method. I appreciate any help or hint. Thank you.
public interface IBasicModel {
string _id { get; set; }
}
public class SomeModel: IBasicModel {
public string _id { get; set; }
/* some other properties! */
}
public interface ISomeModelAbstract<T> where T: IBasicModel
{
bool Save(T model);
T GetById(string id);
IEnumerable<T> GetAll();
bool Update(string id, T model);
bool Delete(string id);
}
public abstract class SomeModelAbstract<T> : ISomeModelAbstract<T> where T : IBasicModel
{
public bool Save(T model)
{
throw new System.NotImplementedException();
}
public T GetById(string id)
{
throw new System.NotImplementedException();
}
public IEnumerable<T> GetAll()
{
throw new System.NotImplementedException();
}
public bool Update(string id, T model)
{
throw new System.NotImplementedException();
}
public bool Delete(string id)
{
throw new System.NotImplementedException();
}
}
public interface IConcreteClass: ISomeModelAbstract<SomeModel> { }
public class ConcreteClass: SomeModelAbstract<SomeModel>, IConcreteClass { }
This doesn't work because of Covariance concern. Consider this sample code.
public class SomeModel2: IBasicModel {
public string _id { get; set; }
/* some other properties! */
}
After that, you can pass for example some object of SomeModel2 to Save method of x and obviously, this is not OK.
ISomeModelAbstract<IBasicModel> x = new ConcreteClass();
var m = new SomeModel2();
x.Save(m);
To preventing this you should tell implicitly that you use your generic type only in return (out) places, not in inputs. For example:
public interface ISomeModelAbstract<out T> where T: IBasicModel
And after doing this, unfortunately, you can't use Save and Update method in your ISomeModelAbstract interface. Because they use T in parameter (input) place.
For more information please see link below: http://tomasp.net/blog/variance-explained.aspx/
Another answer already describes the reason why it doesn't work in current state. I want to add that in such cases it's often useful to extract covariant or contravariant parts of your interface (or both) into separate interface(s). For example:
// covariant part, T is used only as return value
// ISomeModelRead is not the best name of course
public interface ISomeModelRead<out T> where T : IBasicModel {
T GetById(string id);
IEnumerable<T> GetAll();
}
// the rest of interface, also implementing covariant part
public interface ISomeModelAbstract<T> : ISomeModelRead<T> where T : IBasicModel {
bool Save(T model);
bool Update(string id, T model);
bool Delete(string id);
}
Now everything works the same, except you can do:
ISomeModelRead<IBasicModel> x = new ConcreteClass();
x.GetAll();
x.GetById("id");
In order to use dependency injection in .NET Core, we've built a bunch of repository interfaces for our controllers to use for database interactions.
We have a EntityBase class that has some methods in it, and our generic repository interface uses that base class like: IRepository<T> where T : EntityBase.
I want to add a more specific TaggedEntityBase class that extends EntityBase to represent the fact that we have some Entities which we want to filter by tags. I want TaggedEntityBase to have an abstract property which I can use in my controller so that I can abstract out and reuse the filtering method.
So what I want is something like this, but I think I want ITaggedRepository to also inherit from IRepository so that a class implementing ITaggedRepository is guaranteed to have a ListAll method and a ListWithTags method:
public class EntityBase { }
public abstract class TaggedEntityBase : EntityBase
{
public string TagIDs { get; }
}
public interface IRepository<T> where T : EntityBase
{
IEnumerable<T> ListAll();
}
public interface ITaggedRepository<T> where T : TaggedEntityBase
{
IEnumerable<T> ListWithTags(System.Linq.Expressions.Expression<Func<T, bool>> predicate);
}
I'm fairly certain that I've just thoroughly confused myself by pursuing this line of thinking, but I'm not sure how to do what I really want here. I know I need to keep things abstract for dependency injection, but I feel like I'm butting up on the edge of what's possible with interfaces.
Is there a better line of thinking that will get me where I'm trying to go?
You can go ahead and inherit from IRepository<T>:
public interface ITaggedRepository<T> : IRepository<T> where T : TaggedEntityBase
{
IEnumerable<T> ListWithTags(Expression<Func<T, bool>> predicate);
}
At some point you may into trouble if your TaggedEntity is not really an abstraction. Say you have NamedEntities also and some are Tagged.
Now you have a INamedRepository, ITaggedRepository and a INamedTaggedRepository (you'll run into similar issues on your base entity).
You could do a more trait like thing like:
public class EntityBase {}
public interface ITagged
{
string TagIDs { get; }
}
public interface INamed
{
string Name { get; }
}
public class Book : EntityBase, ITagged, INamed
{
public string TagIDs { get; set; }
public string Name { get; }
}
public interface IRepository<T> where T : EntityBase
{
IEnumerable<T> ListAll();
}
public interface IQueryTags<T> where T : ITagged
{
IEnumerable<T> ListWithTags(Expression<Func<T, bool>> predicate);
}
public interface IQueryByName<T> where T : INamed
{
T GetByName(string name);
}
public interface IBookRepository : IRepository<Book>, IQueryTags<Book>, IQueryByName<Book>
{
}
public class ConcreteBookRepository: IBookRepository
{
public IEnumerable<Book> ListAll()
{
throw new NotImplementedException();
}
public IEnumerable<Book> ListWithTags(Expression<Func<Book, bool>> predicate)
{
throw new NotImplementedException();
}
public Book GetByName(string name)
{
throw new NotImplementedException();
}
}
In the concrete implementation you could, through composition, use a ByNameQueryer, TagQueryer and some concrete Repository.
I don't really like generic repositories, so I tend to rename IRepository to IStore since it usually only contains the CRUD aspect typically.
Oh and then some entities you can't delete, some can't be updated. You will end up breaking that down to IAdd, IUpdate, IDelete etc. This is where you start to wonder if this was actually a good idea also ;-)
I have two separate databases for storing documents and users. Also I've implemented generic repository pattern:
public class Repository<T> : IRepository<T> where T : class
{
public DbContext Context { get; set; }
public Repository()
{
}
public IEnumerable<T> Get(Expression<Func<T, bool>> expression)
{
return Context.Set<T>().Where(expression).AsEnumerable();
}
public void Add(T entity)
{
Context.Set<T>().Add(entity);
}
public void Delete(T entity)
{
Context.Set<T>().Remove(entity);
}
public void Update(T entity)
{
Context.Set<T>().Attach(entity);
Context.Entry<T>(entity).State = EntityState.Modified;
}
public void SaveChanges()
{
Context.SaveChanges();
}
}
The problem is that entities are stored in different DbContexts and I can't use something like this:
container.Register(Component.For(typeof(IRepository<>)).ImplementedBy(typeof(Repository<>));
How can I specify which DbContext should be used for each entity?
For example, if I want create Repository that means that one database should be used, but if I want Repository another context should be used.
Or I should create two repo classes, like this:
public class AttachmetRepository<T> : IRepository<T> where T : class
{
public AttachmetsDbContext Context { get; set; }
...
}
public class UserRepository<T> : IRepository<T> where T : class
{
public UsersDbContext Context { get; set; }
...
}
The reason why I don't want to use two different repositories is to keep services simple, something like this:
public class SomeService: ISomeService
{
public IRepository<User> UserRepository { get; set; } //database 1
public IRepository<Comment> CommentsRepository { get; set; } //database 1
public IRepository<Attachment> AttachmentRepository { get; set; } //database 2
...
}
UPD:
As Ognyan suggested I've used FactoryMethod and this helped! Thanks a lot, Ognyan!
I'm new to CastleWindsor and I'm not sure its the best and fastest way, but here is my code:
public class EFDatabaseInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For<AttContext>().LifeStyle.PerWebRequest);
container.Register(Component.For<DefContext>().LifeStyle.PerWebRequest);
container.Register(Component.For(typeof(IRepository<>)).UsingFactoryMethod((kernel, context) =>
{
var genericType = context.RequestedType.GetGenericArguments()[0];
Type type = typeof(Repository<>).MakeGenericType(genericType);
object repository = Activator.CreateInstance(type);
PropertyInfo dbContextProperty = type.GetProperty("Context");
if (genericType == typeof(Attachment))
{
dbContextProperty.SetValue(repository, kernel.Resolve<AttContext>());
}
else
{
dbContextProperty.SetValue(repository, kernel.Resolve<DefContext>());
}
return repository;
}).LifeStyle.PerWebRequest);
}
}
First you need not to hard code the DbContext inside the repository. You can remake your repository like this :
public class Repository<T> : IRepository<T> where T : class
{
private readonly DbContext _dbContext;
// you can even make it IDbContextProvider with .Current() method in order not
// to place a hard dependency but depend on Interface which is the proper way.
// I was in a hurry and did not want to overcomplicate the implementation.
public Repository(DbContext dbContext)
{
_dbContext = dbContext;
}
protected IDbSet<T> CreateSet<T>() where T : class
{
return _dbContext.Set<T>();
}
public virtual T Find(int id)
{
return CreateSet<T>().Find(id);
}
...
}
After that you need a factory method and a way to distinguish the destination db. One way to distinguish is to get the info from the CreationContext of the factory method :
private static DbContext DbContextFactoryMethod(IKernel k, ComponentModel cm, CreationContext c)
Here you can traverse the resolution stack and see if this is part of graph that contains IRepository or other entity and choose your database.
This way you will get the proper DbContext inside your repository without sticking all of them inside which will become more and more cumbersome with time.
I have the following domain object:
public class DomainObject<T,TRepo>
where T : DomainObject<T>
where TRepo : IRepository<T>
{
public static TRepo Repository { get;private set; }
}
A repository interface:
public interface IRepository<T> //where T : DomainObject<T> // The catch 22
{
void Save(T domainObject);
}
An implementation of the 2:
public class User : DomainObject<User,MyRepository>
{
public string Name { get;private set;}
}
public class MyRepository : IRepository<User>
{
public List<User> UsersWithNameBob()
{
}
}
So adding another method that isn't inside IRepository.
I want to enforce the repository as an IRepository while above it could be any type.
A small sidenote: I'm writing this for small systems with very few domain objects. I'm not looking to create anything that uses IoC, but rather something that is easy and simple to consume.
Thanks
Your implementation of DomainObject is only specifying one generic type argument instead of two. Why isn't it:
public class User : DomainObject<User, MyRepository>
{
public string Name { get;private set;}
}
If that doesn't work, could you explain in what way it doesn't do what you need?
Not exactly sure what you want, but something like this compiles:
public class DomainObject<T, TRepo>
where T: DomainObject<T, TRepo>
where TRepo: IRepository<T, TRepo>
{
public static TRepo Repository
{
get;
private set;
}
}
public interface IRepository<T, TRepo>
where T: DomainObject<T, TRepo>
where TRepo: IRepository<T, TRepo>
{
void Save(T domainObject);
}