How to implement multiple instances of interface for different subclasses? - c#

I have a large class that used to hold different information for two different sets of the same class. For example, say a receipt that can be a customer receipt or an internal receipt. All this information is in one giant class because that's how the database is structured, but I want to separate the classes so that I would have a receipt class that holds all the shared information, a customer receipt class, and an internal receipt class. They could share an interface, but the implementations would be different, and that is what is confusing me.
Should there be two separate interfaces that get implemented? So I would have an ICustomerReceipt and IInternalReceipt? I thought there should be one interface with say a Get() and Save() method, and based on the implementation if it's a customer or internal receipt, I get the information specific to the class. I'm a bit lost here.
public class Receipt {
public int ID { get; set; }
public int ReceiptNumber { get; set; }
public List<string> Items { get; set; }
}
public class CustomerReceipt : Receipt {
public string CustomerNumber { get; set; }
public string CustomerEmail { get; set; }
public string CustomerOption { get; set; }
}
public class InternalReceipt : Receipt {
public string InternalNumber { get; set; }
public string InternalEmail { get; set; }
public string InternalOption { get; set; }
}
public interface IReceiptRepository {
public Receipt Get(int id);
public Receipt Add(Receipt receipt);
}
public CustomerReceiptRepository : IReceiptRepository {
public CustomerReceipt Get(int id) {
// get information about customer receipts here
}
}
public InternalReceiptRepository: IReceiptRepository {
public InternalReceipt Get(int id) {
// get information about internal receipts here
}
}
Basically I just want to return the correct Receipt to a view model in my controller that just has the generic 'ReceiptNumber' or 'ReceiptEmail'. I know it's not the best example, but it's the only one I could come up with.

Don't get tripped up on trying to force two similar things to share a single abstraction (base class or interface). So, I'd recommend what you suggested: create two separate interfaces.
Remember, the point of polymorphism is so you don't have to know what specific (derived/implemented) type an instance is if you're only looking for an instance of the base type/interface. That's it. If you don't need that, then jumping through hoops to force two similar classes to share a base is not worth it.

public interface IReceiptRepository {
public Receipt Get(int id);
public Receipt Add(Receipt receipt);
}
public CustomerReceiptRepository : IReceiptRepository {
public Receipt Get(int id) {
// get information about customer receipts here
return new CustomerReceipt();
}
}
public InternalReceiptRepository: IReceiptRepository {
public Receipt Get(int id) {
// get information about internal receipts here
return new InternalReceipt();
}
}

Inheritance can be represented on the database in different ways and there are some strategies depending on the ORM you are using.
At the end of the day, using one of the strategies, you can base your repository on the base class and let the ORM act as a proxy to resolve the instance you need, or try to recreate yourself, at the level of the repository, based on a discriminator field, the instances you need
Receipt
ID
ReceiptNumber
CustomerNumber
CustomerEmail
CustomerOption
InternalNumber
InternalEmail
InternalOption
DISCRIMINATOR_FIELD
(most of the ORM do this translation for you), but for you to get the idea, you can keep only one repository to treat all the classes as Receipt and keep your hierarchy as you have it.
public interface IReceiptRepository {
public Receipt Get(int id);
public Receipt Add(Receipt receipt);
}
public CustomerReceiptRepository : IReceiptRepository {
public Receipt Get(int id) {
var rec = DbContext.Table.Receipt.FirstOrDefault(r => r.id = id);
if(rec.DiscriminatorField == 1) //CustomerReceipt
{
return new CustomerReceipt
{
ID = ...
ReceiptNumber = ...
CustomerNumber = ...
CustomerEmail = ...
CustomerOption = ...
}
}
//all other cases are InternalReceipts
return new InternalReceipt
{
ID = ...
ReceiptNumber = ...
InternalNumber = ...
InternalEmail = ...
InternalOption = ...
}
}
}
The same thing for the Add method, just fill only the fields you need for that object. This composition is basing everything on a discriminator field. I am not suggesting you implement your solution in that way, but with that, you still get on your ViewModel the generic receipt. My suggestion is that you read more about the ORM you are using an how you can represent inheritance there(maybe you are using database first instead of code first and you will need to handle the things manually, because the database was not designed on that way and you need to take a similar approach of what I suggested. But if you have the chance to create your POCO classes and create the database, definitely it deserves to take a look at how they implement the inheritance.
Here I am attaching a link of how this problem is addressed on EntityFramework 6
Inheritance Strategy in Entity Framework 6
Hope this helps

Related

Pre-filtering results with entity framework database-first

Using EF database-first, is it possible to create a duplicate of one of the classes, such that any query made comes back with an additional filter?
As an example: Given a class
public partial class Person
{
public Person()
{
this.Job= new HashSet<Appointments>();
}
public int PersonID { get; set; }
public int JobID { get; set; }
public string Forename { get; set; }
public string Surname { get; set; }
public virtual ICollection<Appointments> Appointments { get; set; }
}
Is it possible to construct a duplicate of the class in some way that functions like the existing class, but will only return results applied a "where Forename = 'David')
I can't overwrite the existing class (both cases need to be kept, and it'll be overwritten anyway)
My first thought was to simply create a seperate static class with methods that return an IQueryable< Persons>, but to then call that later, the context has been disposed - I don't think you can attach it to a new context?
The best you could do would be to add a function to your DbContext, in a partial class, that returns an IQueryable<Persons> with the filter already applied.
The partial class should have the same name as your actual context class. Any code in the partial class will be merged with the Database-First generated class, as if they were in the same file. It also won't get touched or overwritten by the code-generator if you regenerate the context. You can use this same concept to extend all kinds of code-generated classes (this is exactly the kind of use-case that partial classes were designed for).
public partial class MyDbContext
{
public IQueryable<Persons> FilteredPersons()
{
return this.Persons.Where(p => p.Forename =="David");
}
}
Then you can call it like this:
using (var myContext = new MyDbContext())
{
var query = myContext.FilteredPersons().Where(...some additional filter...);
var results = query.ToList();
}
You could probably also rig something up with an IDBCommandInterceptor, but that would be huge, hacky, ugly, and beyond the scope of a simple answer like this.

Objects relationship (between objects in different collections) in MongoDB

TL/DR: I have two Models each with its own repository, context and controller for MongoDB. How do I build relationships between them similar to how RDBMS would use ForeignKey to reference one model from another.
So I have two models, one referencing another one:
[Validator(typeof(OrgNameValidator))]
public class Org : BaseEntity
{
public string Name { get; set; }
}
public class Portfolio : BaseEntity
{
public string Name { get; set; }
public bool IsPrivate { get; set; }
public Org Organization { get; set; }
}
I use MongoDB as backend so each of the two has their own context, repository and controller (This may be right or wrong, but for the education purposes I am trying to focus on the task of managing relationship between MongoDB documents that is abstracted from the representation at the model/class level).
My attempt is that when I save a Portfolio, at the database level, it will create a document in the Portfolio collection that has a field for Org with ObjectID referencing a document in the Org collection.
So I am trying to POST a new Portfolio:
[HttpPost]
public async Task<IActionResult> Post([FromBody] Portfolio portfolio)
{
try
{
if (ModelState.IsValid)
{
await _repository.AddRecord(portfolio);
return new OkObjectResult(portfolio);
}
else
{
return await Task.FromResult(BadRequest(ModelState));
}
}
catch (Exception ex)
{
return await Task.FromResult(StatusCode(500, ex.Message));
}
}
So there are two scenarios that happen:
When passing Org _Id for Organization field (similar with how some other frameworks let you do this) - you end up with invalid input problem: the Organization field is Org class so it won't validate and I think I am missing some object mapping or something else that potentially comes out of box with AspNetCore.MVC that would allow me to mitigate this.
When giving it all Org details - will save the Org details inline Portfolio document in its own Portfolio collection. I assume this is logical since from the object perspective, Org is an Org so it validates the object and nests it into the document - how would it "know" that it needs to save the document in a different collection via a different repository implementation.
I would assume that I could convert things a little to actually be this (having Organization be represented as string storing it's _id and then working out the logic of retrieving the relevant data via getters in Portfolio class):
public class Org : BaseEntity
{
public string Name { get; set; }
}
public class Portfolio : BaseEntity
{
public string Name { get; set; }
public bool IsPrivate { get; set; }
public string Organization { get; set; }
public getOrganization{get{return _repo<Org>.getOrgById(this.Organization)}}
}
I am still thinking that there must be something I am missing that will allow me to keep the "conventional" model/class structure similar to how I would have it with RDBMS implementations while having a document-oriented storage at the backend.
Another option here is using MongoDBRef type to reference other documents but it requires a bit of coding to align this to be flexible across modelling entities. I looked for MongoDB repository/entity frameworks implementations and found a few (Yarn, MongoRepository, Simple.Data, SharpRepository) but none are compatible with AspNetCore yet.
What is the pattern in asp.net core that allows me to orchestrate object relationships between different models and objects with MongoDB?

Domain Model and related data (anemic domain model)

I'm currently working with ASP .NET Core 1.0 using Entity Framework Core. I have some complex calculations with data from the database and I'm not sure how to build a proper architecture using Dependency Injection without building an anemic domain model (http://www.martinfowler.com/bliki/AnemicDomainModel.html)
(Simplified) Example:
I have the following entities:
public class Project {
public int Id {get;set;}
public string Name {get;set;}
}
public class TimeEntry
{
public int Id {get;set;}
public DateTime Date {get;set;}
public int DurationMinutes {get;set;}
public int ProjectId {get;set;}
public Project Project {get;set;}
}
public class Employee {
public int Id {get;set;}
public string Name {get;set;}
public List<TimeEntry> TimeEntries {get;set;}
}
I want to do some complex calculations to calculate a monthly TimeSheet. Because I can not access the database within the Employee entity I calculate the TimeSheet in a EmployeeService.
public class EmployeeService {
private DbContext _db;
public EmployeeService(DbContext db) {
_db = db;
}
public List<CalculatedMonth> GetMonthlyTimeSheet(int employeeId) {
var employee = _db.Employee.Include(x=>x.TimeEntry).ThenInclude(x=>x.Project).Single();
var result = new List<CalculatedMonth>();
//complex calculation using TimeEntries etc here
return result;
}
}
If I want to get the TimeSheet I need to inject the EmployeeService and call GetMonthlyTimeSheet.
So - I end up with a lot of GetThis() and GetThat() methods inside my service although this methods would perfectly fit into the Employee class itself.
What I want to achieve is something like:
public class Employee {
public int Id {get;set;}
public string Name {get;set;}
public List<TimeEntry> TimeEntries {get;set;}
public List<CalculatedMonth> GetMonthlyTimeSheet() {
var result = new List<CalculatedMonth>();
//complex calculation using TimeEntries etc here
return result;
}
}
public IActionResult GetTimeSheets(int employeeId) {
var employee = _employeeRepository.Get(employeeId);
return employee.GetTimeSheets();
}
...but for that I need to make sure that the list of TimeEntries is populated from the database (EF Core does not support lazy loading). I do not want to .Include(x=>y) everything on every request because sometimes I just need the employee's name without the timeentries and it would affect the performance of the application.
Can anyone point me in a direction how to architect this properly?
Edit:
One possibility (from the comments of the first answer) would be:
public class Employee {
public int Id {get;set;}
public string Name {get;set;}
public List<TimeEntry> TimeEntries {get;set;}
public List<CalculatedMonth> GetMonthlyTimeSheet() {
if (TimeEntries == null)
throw new PleaseIncludePropertyException(nameof(TimeEntries));
var result = new List<CalculatedMonth>();
//complex calculation using TimeEntries etc here
return result;
}
}
public class EmployeeService {
private DbContext _db;
public EmployeeService(DbContext db) {
_db = db;
}
public Employee GetEmployeeWithoutData(int employeeId) {
return _db.Employee.Single();
}
public Employee GetEmployeeWithData(int employeeId) {
return _db.Employee.Include(x=>x.TimeEntry).ThenInclude(x=>x.Project).Single();
}
}
public IActionResult GetTimeSheets(int employeeId) {
var employee = _employeeService.GetEmployeeWithData(employeeId);
return employee.GetTimeSheets();
}
Do not try to solve querying problems with your aggregates. Your aggregates are meant to process commands and protect invariants. They form a consistency boundary around a set of data.
Is the Employee object responsible for protecting the integrity of an employee's timesheet? If it doesn't then this data doesn't belong into the Employee class.
Lazy-loading may be fine for CRUD models, but is usually considered an anti-pattern when we design aggregates because those should be as small and cohesive as possible.
Are you taking business decisions based on the calculated result from timesheets? Is there any invariants to protect? Does it matter if the decision was made on stale timesheet data? If the answer to these questions is no then your calculation is really nothing more than a query.
Placing queries in service objects is fine. These service objects may even live outside the domain model (e.g. in the application layer), but there is no strict rule to follow. Also, you may choose to load a few aggregates in order to access the required data to process the calculations, but it's usually better to go directly in the database. This allows a better separation between your reads & writes (CQRS).
If I understood your question correctly you can use a trick with injecting a service into your entities that helps it do the job, e.g.:
public class Employee()
{
public object GetTimeSheets(ICalculatorHelper helper)
{
}
}
Then in your service that holds the employees you would obtain it in the constructor and pass to the employee class for calculations. This service can be a Facade e.g. for getting all the data and perform initialization or whatever you really need.
As for the TimeEntries, you can get them using a function like this:
private GetTimeEntries(ICalculationHelper helper)
{
if (_entries == null)
{
_entries = helper.GetTimeEntries();
}
return _entries;
}
It depends of course on you strategy of caching and so on if this pattern fits you.
Personally I find it rather easy to work with anemic classes and have a lot of the business logic in services. I do put some in the objects, like e.g. calculating FullName out of FirstName and LastName. Usually stuff that does not involve other services. Though it's a matter of preference.

Abstract away the DAL from Entity Framework implementation

First of all I'm sorry if this is going to be a long post, but I don't know how to explain the problem in the correct way without the required details.
I'm having troubles finding a way to abstract my DAL from an Entity Framework implementation. The project I'm working on is very small, but if in future I'd want to switch to another ORM like NHibernate, or just plain ADO.NET, I'd like to write code just for the implementation, not the entire DAL.
Say I have these entities in my MyWallet.DAL:
public interface IWallet {
long Id { get; set; }
float TotalAmountOfMoney { get; set; }
long CurrencyId { get; set; }
ICurrency Currency { get; set; }
DateTime RecordedOn { get; set; }
ICollection<IMoneyMovement> MoneyMovements { get; set; }
}
public interface ICurrency {
long Id { get; set; }
char Symbol { get; set; }
string Code { get; set; }
string Description { get; set; }
}
public interface IMoneyMovement {
long Id { get; set; }
float Amount { get; set; }
string Description { get; set; }
long WalletId { get; set; }
IWallet Wallet { get; set; }
DateTime RecordedOn { get; set; }
DateTime MovedOn { get; set; }
}
As you can see these are plain interfaces which I plan to implement on another library which will contain the actual Entity Framework implementation (say MyWallet.DAL.EntityFramework). Of course I'm going to decorate the entities implementation with Entity Framework specific attributes as [Key] or [ForeignKey] and stuff like that.
I also defined some repository in MyWallet.DAL like IWalletRepository, IMoneyMovementRepository, ICurrencyRepository to gain access to the entities. Actually I don't know if this is the right way to design access to the entities. Of course I also defined factories to get the concrete implementation of the entities.
In my business layer I defined services to handle the object request, work with the DAL entities and return a business object, like this:
public class WalletService {
private readonly IWalletRepository _walletRepository;
private readonly IWalletFactory _walletFactory;
public WalletService(IWalletRepository walletRepository,
IWalletFactory walletFactory) {
_walletRepository = walletRepository;
_walletFactory = walletFactory;
}
public CreatedWallet CreateWallet(CreateWalletRequest request) {
var wallet = _walletFactory.Create();
wallet.CurrencyId = request.CurrencyId;
wallet.TotalAmountOfMoney = request.TotalAmountOfMoney;
wallet.RecordedOn = DateTime.Now;
_walletRepository.Create(wallet);
_walletRepository.SaveChanges();
return new CreatedWallet {
Id = wallet.Id
}
}
}
I thought this was going to work seamlessly, or at worst - in a situation when I've got more than one repository - I could share the DataContext so I'd need to fire the SaveChanges method on just one to reflect the changes on the database.
The problem is with the repository implementation, in this case I'll continue with Entity Framework:
public class EFDataContext : DbContext {
public EFDataContext() : base ("name=MyConnectionString") {
}
public virtual DbSet<EFWallet> Wallets { get; set; }
public virtual DbSet<EFMoneyMovement> MoneyMovements { get; set; }
public virtual DbSet<EFCurrency> Currencies { get; set; }
}
public class EFWalletRepository : IWalletRepository {
private readonly EFDbContext _dataContext;
public EFWalletRepository(EFDbContext dataContext) {
_dataContext = dataContext ?? new EFDbContext();
}
public int SaveChanges() {
return _dataContext.SaveChanges();
}
public void Dispose() {
_dataContext.Dispose();
}
public void Create(IWallet wallet) {
...???
}
}
Now that's the problem: how do I work with interfaces when the DataContext knows only about concrete implementations? Am I doing this all wrong?
UPDATE:
Ok so, basically, as stated out by #TomTom, why fight Entity Framework when you could just embrace its power? I guess I'll just let EF be the abstraction. In fact, by letting EF act as the DAL, you can just focus on the business logic of your project.
And to put it all together and respond to #tdragon regarding the repositories / unit of work issue: yes, I could either wrap multiple repositories inside an unit of work or simply let the DbContext be the unit of work:
public class EFWalletRepository : IWalletRepository {
private readonly EFDbContext _dataContext;
public EFWalletRepository() {
_dataContext = new EFDbContext();
}
public void Dispose() {
_dataContext.Dispose();
}
public IEnumerable<Wallet> Wallets {
get { return _dataContext.Wallets; }
}
public void SaveWallet(Wallet wallet) {
if (wallet.Id == 0) {
_dataContext.Wallets.Add(wallet);
} else {
var databaseEntry = _dataContext.Wallets.Find(wallet.Id);
//update properties
}
_dataContext.SaveChanges();
}
}
Simply speaking: yes, you do it wrong. You introduce a bad abstraction (that costs you dearly in functionality) "because of". EF already is an abstraction.
Any abstraction on top of it will cost you in terms of functionality used - which in terms of databases comes with a big performance impact. Want an example? "Include" to preload navigation properties (instead of lazy loading). You will have to work around this and a lot of more detailed behavior that is ORM specific - for the gain of having what? And if you give up on those higher more specific functions your performance WILL suffer.
I can't see any reason to abstract your model (entities). Do you expect them to change when you change the way you access your database?
But if you want to keep it that way, you can make your repository interfaces generic, and pass the concrete entity type when defining repository, so you would end up with:
public class EFWalletRepository : IWalletRepository<EFWallet>
{
public void Create(EFWallet wallet)
{
_dataContext.Add(wallet);
}
}
Other suggestions:
You should not expose sets for your model properties. It's against OOP rules - you should rather expose some methods to manipulate the objects, the state should be more internal.
You probably should not add SaveChanges() method to your repository - this should be a "unit of work" job to commit all changes to the database.
You would face a problem when you would use more than one repository in your service layer, as you create a new DbContext for repository, when you should have one for single "unit of work".

How do I get the .ToList to show when reading from a repository...Where am I going wrong?

For some reason, C# wont show me the .ToList on my code. I am wondering how to get it.
I have a basic MVC4 app which I successfully divided into several projects as a proof of concept. So here are my layers...Everything works until I try to add a domain layer. This is where the confusion starts. So some code:
My model is generated from the database by EF5. I have a standard "Student" class with an ID and a Name. This is all. It relates to a course. A course has many students. Here is what EF Generates.
public partial class Student
{
public int Id { get; set; }
public Nullable<int> CourseId { get; set; }
public string Name { get; set; }
public Nullable<System.DateTime> DateAttended { get; set; } //This field becomes important later
public virtual Course Course { get; set; }
}
Here is the course model.
public partial class Course
{
public Course()
{
this.Student = new HashSet<Student>();
}
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<Student> Student { get; set; }
}
I extracted this out to a Models project and fully tested everything after. All went well, no problems there.
Then I added a generic repo layer between this and my controller to remove the DB access logic from my controllers. Here is the interface:
public interface IHeadRepository<TEntity>
{
ICollection<TEntity> ReadAll(); //I Want to focus here for the problem...
int Create(TEntity entity);
TEntity ReadSingle(int id);
ICollection<TEntity> ReadSome(Expression<Func<TEntity, bool>> predicate);
int Update(TEntity entity);
int Delete(TEntity entity);
}
I will only show the implementation of the part I want to focus on for brevity...
public class HeadRepo<TEntity> : IHeadRepository<TEntity> where TEntity : class
{
protected DbSet<TEntity> dbSet;
private readonly DbContext dbContext;
public HeadRepo() { }
public HeadRepo(DbContext dbContext)
{
this.dbContext = dbContext;
dbSet = dbContext.Set<TEntity>();
}
public ICollection<TEntity> ReadAll()
{
return dbSet.ToList();
}
}
Before I started trying to implement my domain layer, I tested everything and it all worked. So I proceeded to implement my domain layer and made a few changes to my repo.
Origionally both the interface and repo looked like this...
public IQueryable<TEntity> ReadAll()
{
return dbSet;
}
It was an Iqueriable instead of a ICollection. I tried all kinds of changes, IList, IEnumerable etc.
Finally...The problem I am having seems to be with my controller...But I am aware that it could be because of the way I implemented the repo. However I don't know how to fix it.
So here is my controller...The index action.
This is the before. It worked fine.:
public ActionResult Index()
{
return View(studentRepo.ReadAll());
}
What I am trying to do (and I know I could do this simple task in any number of places but I want to get it working here and extract it later) is add a ViewModel which has an extra field called something like YearsGraduated. Like this:
public class StudentVM : Student
{
[Display(Name = "Years Graduated:")]
public int YearsGraduated { get; set; }
}
Then I want to go to my controller and, use my repo to read all the students, assign the list of students to my list of studentVM's and then run a simple method on them to calculate the years since they graduated. So here it is in SemiSudo...
public ActionResult Index()
{
//I get an error when I do this (the best overloaded...has invalid args)
//var vm = new List<StudentVM>(studentRepo.ReadAll());
//So I try this:
//var vm = new List<StudentVM>();
//vm = studentRepo.ReadAll(); //I get error here...Cannot implicity comvert...explisit exists
//So I try this:
//var vm = new List<StudentVM>();
//vm = studentRepo.ReadAll().ToList(); //I get error here...No definition / extension method .ToList() can be found
//So I tried updating my repo interface and changing it from:
//IQueriable to ICollection
//ICollection to IEnumerable
//IEnumerable to IList
//IList to List
//Without any success.
//As explained, if I can get this working, I would like to do something like:
//
//var vm = new List<StudentVM>();
//vm = studentRepo.ReadAll();
//For(i=0; i<vm.count; i++)
//{
// vm[i].YearsGraduated = CalcYearsExpired(vm[i].DateAttended)
//}
//Some method outside this called CalcYearsExpired() which takes a date,
//returns an int or double and im done.
//Then the return method changes from this:
//return View(studentRepo.ReadAll());
//To something like this:
//return View("Index", vm);
//And the view changes accordingly to use the Collection<StudentVM> to list the students.
}
Any help would be greatly appreciated...My goal would be to add a domain layer and extract this code when working so my controller stays simple. I am having great difficulty doing this so obviously there is no point in trying to do it elsewhere if I cant do it locally in the controller or repo first. I don't want to put it into the repo because it will make the repo to specific and I want to try keep it generic. But my priority is to resolve the problem so if I have to make the repo more specific I would.
Include the namespace System.Linq if not?

Categories

Resources