First off, I think this is somewhat ridiculous to do but the other members of my team insist upon it and I can't come up with a good argument against it other than "I think it's dumb"...
What we're trying to do is create a completely abstract data layer and then have various implementations of that data layer. Simple enough, right? Enter Entity Framework 4.1...
Our end goal here is that the programmers (I do my best to stay only on the data layer) never want to have to be exposed to the concrete classes. They only ever want to have to use interfaces in their code, aside from obviously needing to instantiate the factory.
I want to achieve something like the following:
First we have our "Common" library of all of the interfaces, we'll call it "Common.Data":
public interface IEntity
{
int ID { get; set; }
}
public interface IUser : IEntity
{
int AccountID { get; set; }
string Username { get; set; }
string EmailAddress { get; set; }
IAccount Account { get; set; }
}
public interface IAccount : IEntity
{
string FirstName { get; set; }
string LastName { get; set; }
DbSet<IUser> Users { get; set; } // OR IDbSet<IUser> OR [IDbSet implementation]?
}
public interface IEntityFactory
{
DbSet<IUser> Users { get; }
DbSet<IAccount> Accounts { get; }
}
From that we then have an implementation library, we'll call it "Something.Data.Imp":
internal class User : IUser
{
public int ID { get; set; }
public string Username { get; set; }
public string EmailAddress { get; set; }
public IAccount Account { get; set; }
public class Configuration : EntityTypeConfiguration<User>
{
public Configuration() : base()
{
...
}
}
}
internal class Account : IAccount
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DbSet<IUser> Users { get; set; } // OR IDbSet<IUser> OR [IDbSet implementation]?
public class Configuration : EntityTypeConfiguration<Account>
{
public Configuration() : base()
{
...
}
}
}
Factory:
public class ImplEntityFactory : IEntityFactory
{
private ImplEntityFactory(string connectionString)
{
this.dataContext = new MyEfDbContext(connectionString);
}
private MyEfDbContext dataContext;
public static ImplEntityFactory Instance(string connectionString)
{
if(ImplEntityFactory._instance == null)
ImplEntityFactory._instance = new ImplEntityFactory(connectionString);
return ImplEntityFactory._instance;
}
private static ImplEntityFactory _instance;
public DbSet<IUser> Users // OR IDbSet<IUser> OR [IDbSet implementation]?
{
get { return dataContext.Users; }
}
public DbSet<IAccount> Accounts // OR IDbSet<IUser> OR [IDbSet implementation]?
{
get { return dataContext.Accounts; }
}
}
Context:
public class MyEfDataContext : DbContext
{
public MyEfDataContext(string connectionString)
: base(connectionString)
{
Database.SetInitializer<MyEfDataContext>(null);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new User.Configuration());
modelBuilder.Configurations.Add(new Account.Configuration());
base.OnModelCreating(modelBuilder);
}
public DbSet<User> Users { get; set; }
public DbSet<Account> Accounts { get; set; }
}
Then the front-end programmers would be using it such as:
public class UsingIt
{
public static void Main(string[] args)
{
IEntityFactory factory = new ImplEntityFactory("SQLConnectionString");
IUser user = factory.Users.Find(5);
IAccount usersAccount = user.Account;
IAccount account = factory.Accounts.Find(3);
Console.Write(account.Users.Count());
}
}
So that's pretty much it... I'm hoping someone on here might be able to either point me in the right direction or help me out with a good argument that I can fire back at the development team. I've looked at some other articles on this site about EF not being able to work with interfaces and one reply saying that you can't implement IDbSet (which I find kind of curious, why would they provide it if you couldn't implement it?) but so far to no avail.
Thanks in advance for any help!
J
The first argument is that EF doesn't work with interfaces. DbSet must be defined with a real entity implementation.
The second argument is that your entities should not contain DbSet - that is context related class and your entities should be pure of such dependency unless you are going to implement Active record pattern. Even in such case you will definitely not have access to DbSet of different entity in another entity. Even if you wrap set you are still too close to EF and entity never have property accessing all entities of another entity type (not only those related to current instance).
Just to make it clear DbSet in EF has very special meaning - it is not a collection. It is entry point to database (for example each LINQ query on DbSet hits database) and it is in normal scenarios not exposed on entities.
The third argument is that you are using a single context per application - you have a single private instance per singleton factory. Unless you are doing some single run batch application it is definitely wrong.
The last argument is simply practical. You are paid for delivering features not for wasting time on abstraction which doesn't give you (and your customer) any business value. It is not about proving why you should not create this abstraction. It is about proving why you should do it. What value will you get from using it? If your colleagues are not able to come with arguments which have business value you can simply go to your product manager and let him use his power - he holds the budget.
Generally abstraction is part of well designed object oriented application - that is correct. BUT:
Every abstraction will make your application somehow more complex and it will increase cost and time of development
Not every abstraction will make your application better or more maintainable - too much abstraction has reverse effect
Abstracting EF is hard. Saying that you will abstract data access in the way that you can replace it with another implementation is task for data access gurus. First of all you must have very good experience with many data access technologies to be able to define such abstraction which will work with all of them (and in the end you can only tell that your abstraction works with technologies you thought about when you design that). Your abstraction will work only with EF DbContext API and with nothing else because it is not an abstraction. If you want to build universal abstraction you should start studying Repository pattern, Unit of Work pattern and Specification pattern - but that is a big deal of work to make them and to implement them universal. The first step needed is to hide everything related to data access behind that abstraction - including LINQ!
Abstracting data access to support multiple APIs make sense only if you need it now. If you only think that it can be useful in future than it is in business driven projects completely wrong decision and developer who came with that idea is not competent to make business targeting decisions.
When it make sense to do "a lot of" abstraction?
You have such requirement now - that moves burden of such decision to person responsible for budget / project scope / requirements etc.
You need abstraction now to simplify design or solve some a problem
You are doing open source or hobby project and you are not driven by business needs but by purity and quality of your project
You are working on platform (long living retail product which will live for a long time) or public framework - this generally returns to the first point because this type of products usually have such abstraction as requirement
If you are working only targeted application (mostly single purpose applications on demand or outsourced solutions) the abstraction should be used only if necessary. These applications are driven by costs - the target is delivering working solution for minimal costs and in the shortest time. This target must be achieved even if resulting application will not be very good internally - the only thing which matters is if application meets requirements. Any abstraction based on "what if ... happens" or "perhaps we will need ..." increases costs by virtual (non existing) requirements which will in 99% never happen and in most cases initial contract with customer didn't count which such additional costs.
Btw. this type of applications is targeted by MS APIs and designer strategy - MS will make a lot of designers and code generators which will create non optimal but cheap and quick solutions which can be created by people with smaller skill set and are very cheap. The last example is LightSwitch.
Related
My project is layered as follows:-
DAL (Entity) --> BLL (DTO) --> ApplicationComponent (ViewModel).
There will be multiple components of application (ApplicationComponent) which will access BLL. Components include windows services, web services, web API and MVC controller.
I am transforming NHibernate Entity objects to DTO objects while passing them from DAL to BLL. While passing this state to ApplicationComponent, BLL again converts it to ViewModel.
This helps me separate the concerns and how data is handled in each layer. I am not in favor of returning NHibernate Entity object to view for following reasons: -
Data get exposed to UI that I want to hide (or only expose if needed) like passwords, user type, permission etc.
On references/joins, NHibernate executes additional queries when property is accessed which nullify the use of lazy loading.
Unnecessary data exposed to user (of Entity) creates confusion and gap for bugs.
Persistence implementations leaking into BLL/UI. Entity is not designed for UI. It cannot serve UI in all cases.
We use attributes on DTO properties for user input validation which looks odd with Entity.
I am facing following problems with this approach: -
Biggest and obvious problem is redundant objects with similar members and functionality.
I have to write mapper methods in each layer to transform object. This could be minimized by using AutoMapper or something similar; but it does not fully resolve problem.
Questions:-
Is this an over separation and should be avoided (at least minimized)?
If this approach is correct, I do not see any simple way to fully bypass two problems I stated above. Please suggest.
If this approach is incorrect, please suggest corrections.
References:-
Link1 suggests to transfer Entity object to view which in my understanding not a good idea.
Link2 suggests to map Entity with DTO that I am already doing.
Link3 does not help.
Link4 suggests using something like auto mapper tools which is OK. But it still does not solve the problem completely.
Link5 is great post. It explains why those should be separate which I agree. It does not comment on how to minimize the overhead caused by it.
Link6 is not helpful again.
Link7 is an excellent answer which suggests use Entity as is in UI if possible. It still does not apply to most of my project.
Linl8 is another excellent resource that suggest to go on mapping two way as I am doing now. It still does not suggest a way to minimize overhead.
Have you considered creating a shared interface between the DTO and the Entity? You should not tightly couple your ORM to the rest of your application. Or in fact use anything other than interfaces between them if at all possible.
You could, in theory, have a separate project that just holds the contract/abstractions of what you expect to be passed around. To minimize mapping overhead and to leave it open for the extension you can ensure that the entity implements the interface as expected (omitting what is not needed), and in cases where you need a bespoke DTO you can create a model with mapping using the interfaces.
There is some overhead when adding extra interface projects but it will keep your code cleaner and more maintainable in the long run.
namespace Data
{
public class FakeRepo : IFakeRepo
{
public IThisIsAnEntity GetEntity()
{
return new ThisIsAnEntity();
}
}
public class ThisIsAnEntity : IThisIsAnEntity
{
public string HiddenField { get; set; }
public long Id { get; set; }
public string SomeField { get; set; }
public string AnotherField { get; set; }
}
}
namespace Data.Abstractions
{
public interface IFakeRepo
{
IThisIsAnEntity GetEntity();
}
}
namespace Abstractions
{
public interface IThisIsAnEntity : IThisIsAnSlimmedDownEntity
{
string SomeField { get; set; }
}
public interface IThisIsAnSlimmedDownEntity
{
long Id { get; set; }
string AnotherField { get; set; }
}
}
namespace Services.Abstractions
{
public interface ISomeBusinessLogic
{
IThisIsAnEntity GetEntity();
IThisIsAnSlimmedDownEntity GetSlimmedDownEntity();
}
}
namespace Services
{
public class SomeBusinessLogic : ISomeBusinessLogic
{
private readonly IFakeRepo _repo;
public SomeBusinessLogic(IFakeRepo repo)
{
_repo = repo;
}
public IThisIsAnEntity GetEntity()
{
return _repo.GetEntity();
}
public IThisIsAnSlimmedDownEntity GetSlimmedDownEntity()
{
return _repo.GetEntity();
}
}
}
namespace UI
{
public class SomeUi
{
private readonly ISomeBusinessLogic _service;
public SomeUi(ISomeBusinessLogic service)
{
_service = service;
}
public IThisIsAnSlimmedDownEntity GetViewModel()
{
return _service.GetSlimmedDownEntity();
}
public IComposite GetCompositeViewModel()
{
var dto = _service.GetSlimmedDownEntity();
var viewModel = Mapper.Map<IThisIsAnSlimmedDownEntity, IComposite>(dto);
viewModel.SomethingSpecial = "Something else";
return viewModel;
}
}
public class SomeViewModel : IComposite
{
public long Id { get; set; }
public string AnotherField { get; set; }
public string SomethingSpecial { get; set; }
}
}
namespace UI.Abstractions
{
public interface IComposite : IThisIsAnSlimmedDownEntity, ISomeExtraInfo
{
}
public interface ISomeExtraInfo
{
string SomethingSpecial { get; set; }
}
}
nhibernate is one of those orm`s that allow you to avoid having DAL entities and it will be better for performance to avoid extra mapping from BLL TO DAL, but if it is not critical for you, it will be better to keep it at as it is to have application layers loose coupled
I'm prototyping an ASP.NET Web API that needs to talk to several databases which are almost identical. Each of our customers have their own instance of our database structure, but some are specialized to integrate with other systems they have. So for example in one database the Client table might have the column AbcID to reference a table in another system, but other databases won't have this column. Other than that the two tables are identical in name and columns. The columns can also have different lengths, varchar(50) instead of varchar(40) for example. And in some databases there can be one extra table. I have focused on solving the different columns problem first.
I was hoping to use an ORM to handle the data access layer of the API, and right now I'm experimenting with Entity framework. I already solved how to dynamically connect to the different databases from an API-call, but right now they have to be completely identical in structure.
I have tried to set up double .edmx models with a Database-first approach but this causes conflicting class names between the models. So instead I tried Code-first and come up with this (which isn't working).
DbContext extension:
In the constructor I check which database is being accessed and if it is one of the special ones I flag it for the model configuration.
public partial class MK_DatabaseEntities : DbContext
{
private string _dbType = "dbTypeDefault";
public DbSet<Client> Client { get; set; }
public DbSet<Resource> Resource { get; set; }
public MK_DatabaseEntities(string _companycode)
: base(GetConnectionString(_companycode))
{
if(_companycode == "Foo")
this._dbType = "dbType1";
}
// Add model configurations
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Configurations
.Add(new ClientConfiguration(_dbType))
.Add(new ResourceConfiguration());
}
public static string GetConnectionString(string _companycode)
{
string _dbName = "MK_" + _companycode;
// Start out by creating the SQL Server connection string
SqlConnectionStringBuilder sqlBuilder = new SqlConnectionStringBuilder();
sqlBuilder.DataSource = Properties.Settings.Default.ServerName;
sqlBuilder.UserID = Properties.Settings.Default.ServerUserName;
sqlBuilder.Password = Properties.Settings.Default.ServerPassword;
// The name of the database on the server
sqlBuilder.InitialCatalog = _dbName;
sqlBuilder.IntegratedSecurity = false;
sqlBuilder.ApplicationName = "EntityFramework";
sqlBuilder.MultipleActiveResultSets = true;
string sbstr = sqlBuilder.ToString();
return sbstr;
}
}
ClientConfiguration:
In the configuration for Client I check the flag before mapping properties to database columns. This however does not seem to work.
public class ClientConfiguration : EntityTypeConfiguration<Client>
{
public ClientConfiguration(string _dbType)
{
HasKey(k => k.Id);
Property(p => p.Id)
.HasColumnName("ID")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
if (_dbType == "dbType1")
{
Property(p => p.AbcId).HasColumnName("AbcID");
}
Property(p => p.FirstName).HasColumnName("FirstName");
Property(p => p.LastName).HasColumnName("LastName");
}
}
Client class:
This is how my Client class looks like, nothing weird here.
public class Client : IIdentifiable
{
public int Id { get; set; }
public string AbcId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public interface IIdentifiable
{
int Id { get; }
}
Back-up solution is to use raw SQL queries to deal with the offending tables and ORM for the rest, but it would be awesome if there is some way to do this that I have not thought of. Right now I'm trying Entity framework, but I am not opposed to trying some other ORM if that one can do it better.
Using Code First supports this scenario:
1) Common entities for both models:
public class Table1
{
public int Id { get; set; }
public string Name { get; set; }
}
2) Base version of table 2
public class Table2A
{
public int Id { get; set; }
public int Name2 { get; set; }
public Table1 Table1 { get; set; }
}
3) "Extended" version of table 2, inherits version A, and adds an extra column
public class Table2B : Table2A
{
public int Fk { get; set; }
}
4) Base context, including only the common entities. Note that there is a constructor which accepts a connection string, so there is no parameterless constructor. This forces inheriting contexts to provide their particular connection string.
public class CommonDbContext : DbContext
{
public CommonDbContext(string connectionString)
:base(connectionString)
{
}
public IDbSet<Table1> Tables1 { get; set; }
}
5) The context A, inherits the common context, adds the Table2A, and ignores the Table2B
public class DbContextA : CommonDbContext
{
public DbContextA() : base("SimilarA") { } // connection for A
public IDbSet<Table2A> Tables2A { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Ignore<Table2B>(); // Ignore Table B
}
}
The context B, inherits the common, and includes the Table2B
public class DbContextB: CommonDbContext
{
public DbContextB() :base("SimilarB") { } // Connection for B
public IDbSet Tables2B { get; set; }
}
With this setup, you can instance either DbContextA or DbContextB. One advantage is that both inherit CommonDbContext, so you can use a variable of this base class to access the common entities, no matter if the concrete implementation is version A or B. You only need to change to the concrete type to access the specific entities of A or B (Table2A or Table2Bin this sample).
You can use a factory, or DI or whatever to get the required context depending on the DB. For example this could be your factory implementation:
public class CommonDbContextFactory
{
public static CommonDbContext GetDbContext(string contextVersion)
{
switch (contextVersion)
{
case "A":
return new DbContextA();
case "B":
return new DbContextB();
default:
throw new ArgumentException("Missing DbContext", "contextVersion");
}
}
}
NOTE: this is working sample code. You can of course adapt it to your particular case. I wanted to keep it simple to show how it works. For your case you'll probably need to change the factory implementation, and expose the connection string in A and B context constructors, and provide it in the factory method
Handling the different classes of your entities
The easiest way to handle the different entities of each DbContext is to use polymorphism, and or generics.
If you use polymorphism you need to implement methods which use the type of the base class (as parameter and as return type). This parameters and vars will hold entities either of the base or of the derived class (Table2A or Table2B). In this case, each context will receive an entity of the right type, and it will work directly without trouble.
The problem is when your app is multilayered, uses services or is a web app. In this case when you use the base class the polymorphic behavior can be lost, and you'll need to handle the entities of the base class. (For example if you let the user edit an entity of derived class in a web app form, the form can only take care of the properties of the base class, and when it's posted back, the properties of the derived class will be lost) In this case, you need to handle it intelligently (see note below):
For reading purposes, if you have a Table2B, you have a direct casting to Table2A. You can implement functionality for Table2A and directly used it. I.e. you can return collections or individual values of the base class (in many cases implicit casting will be enough). No more worries.
For inserting/updating, you have to take extra steps, but it's not too difficult. You need to implement methods that receive/return Table2A parameters in your contexts, or in another layer, depending on your architecture. For example, you can make the base context abstract and define virtual methods for this. (See example below). Then you need to make the right implementation for each particular case.
if you receive a Table2A but need to insert it in Table2B, simply map entity A into entity B with AutoMapper or ValueInjecter and fill the remaining properties with default values (beware of AutoMapper and EF dynamic proxies: it won't work).
if you receive a Table2A and need to update a Table2B, simply read the existing entity from the DB and repeat the mapping procedure (ValueInjecter will be less troublesome than AutoMapper also for this case).
This is a very simple example of what can be done, but you need to adapt it to your particular case:
Inside CommonDbContext class, declare virtual methods for the base type, like this:
public virtual Table2A GetTable2AById(int id);
public virtual void InsertTable2A(Table2A table);
You can also use generic interfaces/ methods, instead of abstract class / virtual methods, like this:
public T GetTable2AById<T>(int id)
{
// The implementation
}
In this case you should add the necessary constraints to the T type, like where T: Table2A or the ones you need (class new()).
NOTE It's not exact to say that the polymorphism is lost in this cases, because you can really make polymorphic Web Services with WCF, or Web API, adapt your UI to the real class of your entity (with templates for each case) and so on. That depends on what you need or want to achieve.
Been there, done that.
In all seriousness: dump EF in this specific case; it will bring a lot of pain and suffering for no benefit.
What you'll eventually end up doing (putting my Fortuneteller Hat on) is you'll rip out all the EF-based code, create an abstract object model and then write a series of backends that will map all the various database structures back and forth to said clean abstract object model. And you'll be either using raw SQL or something lightweight like Dapper or BLToolkit.
Now I want to try to start from the objects of my model according to the dictates DDD but I have some difficulty in understanding how to migrate my thought patterns because I can not turn the examples that I find lying around on my specific case .
My main concept are the activities , each activity has an indicative code , a description , a status that changes over time and a quarter each Result.
Users want to be able to see the history of all the states hired from the activities, with the dates on which the changes were made . In addition, they also want to be able to create new states, change the description of the existing ones and possibly prevent the use of some of these while maintaining the value for the previous activities .
Each quarter, users want to be able to insert an Result that contains Outcome and recommendations, a rating and the date of formulation of the outcome .
The ratings must be a list freely maintainable by users.
Thinking to my old way I would create classes like this:
public class Activity
{
public int ID;
public string Desc;
public IList<ActivityStatus> ActivityStatusList;
public IList<Result> ResultList;
}
public class ActivityStatus
{
public Activity Activity;
public Status Status;
public DateTime StartDate;
public DateTime EndDate;
}
public class Status
{
public int ID;
public string Desc;
public bool Valid;
}
public class Result
{
public Activity Activity;
public int Quarter;
public string Outcome;
public string Recommendations;
public Rating Rating;
}
public class Rating
{
public int ID;
public string Desc;
public bool Valid;
}
than i will implement a DataAccessLayer mapping this class to a new db (created from this class) with NHibernate and add repository to grant user CRUD operation to all of this object
According to DDD are there better ways?
I'd recommend to read the book or at least the Wikipedia article.
DDD is about focussing on domain logic and modelling this first - in an object-oriented way. Persistence is a technical concern, which should not be the starting point of your design and (usually) not determine, how you will design your domain classes.
If you're eager to code and believe you understand the domain well, I would suggest a BDD test-first approach. Use tools like SpecFlow to describe your business processes in plain english, then gradually fill in the steps and functionality as you go, using mocks, design patterns, inversion of control etc.
Background reading is a must if you're unfamiliar with DDD. Read the book that EagleBeak suggests, get clued up on SOLID principles and experiment yourself.
I can´t tell if there are better ways but what you said would be one way to solve this problem in a DDD fashion.
In my data access layer I typically use an abstract factory of respositories. This way I can plug an specific implementation for data access such as NHibernate.
public interface IRepositoryFactory {
T Repository<T>();
};
public class NHibernateRepositoryFactory {
T Repository<T>() {
..... // find class that implements T in Assemblies with reflection
return repository;
}
};
public static class Persistence {
IRepositoryFactory Factory { get; set; }
};
This way you can call your repository without referencing any specific implementation:
User user = Persistence.Factory.Get<IUserRepository>().FindByEmail("john#tt.com");
user.name = "James";
Persistence.Factory.Get<IUserRepository>().save(user);
Another advantage of using abstract factories for repositories as above is that you can test your code by pluging a fake implementation for the repository.
public class FakeRepositoryFactory {
T Repository<T>() {
..... // find class that implements T in Assemblies of fake repositories
return repository;
}
};
public class FakeUserRepository : public IUserRepository {
User FindByEmail(string email) {
// create mocked user for testing purposes ....
return userMock;
}
};
Your code will not and should not know where the user data is coming from with abstract factories for persistence. This way switch from one way to another can be done in a transparent way.
I have a IBankAccount interface that I will be passing to the ApplicationService. The changes made on the account objects (in the ApplicationService project) need to be persisted in the database. The repository receives the changes using IBankAccount interface. How can I persist this data into database? This is implemented using LINQ to SQL.
Note: Following is a comment from Scott in http://weblogs.asp.net/scottgu/archive/2007/06/29/linq-to-sql-part-3-querying-our-database.aspx
"Add the interfaces to your LINQ to SQL data model classes. The LINQ to SQL classes are partial classes - which means you could add the interface directly to them."
public class LijosSimpleBankRepository : ILijosBankRepository
{
public System.Data.Linq.DataContext Context
{
get;
set;
}
public virtual void UpdateAccount(DomainInterfaces.IBankAccount iBankAcc)
{
DBML_Project.BankAccount bankAccount;
}
}
namespace DomainInterfaces
{
public interface IBankAccount
{
int BankAccountID { get; set; }
string AccountType { get; set; }
System.Nullable<System.DateTime> OpenedDate { get; set; }
string Status { get; set; }
System.Nullable<int> AccountOwnerID { get; set; }
}
}
namespace DBML_Project
{
public class FixedBankAccount : BankAccount
{
//Note: BankAccount already implemnts IBankAccount
}
public class SavingsBankAccount : BankAccount
{
//Note: BankAccount already implemnts IBankAccount
}
//The auto generated calss is made as abstract
[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.BankAccount")]
[InheritanceMapping(Code = "Fixed", Type = typeof(FixedBankAccount), IsDefault = true)]
[InheritanceMapping(Code = "Savings", Type = typeof(SavingsBankAccount))]
public abstract partial class BankAccount : INotifyPropertyChanging, INotifyPropertyChanged, DomainInterfaces.IBankAccount
{
..
}
}
READING
Optimizing Repository’s SubmitChanges Method
How do you abstract out your persistence code when using LINQ to SQL?
LINQ to SQL - mapping exception when using abstract base classes
Your repository should accept BankAccount - not IBankAccount because Linq-to-sql doesn't know what is IBankAccount and compiler doesn't allow you to store it without casting it first to BankAccount (that can obviously fail at runtime if IBankAccount instance is not a BankAccount).
Once you have BankAccount you simply call:
Context.BankAccounts.Add(account);
Context.SubmitChanges();
As far as I understand you need to model a banking system. This mean dealing with bank accounts. This is tough business that is no "Hello World!"-type information technology.
Basically with bank accounts you need to :
Read details (such as account name, value, etc
Debit account
Credit account
Terminate account
Create a new account
... and other operations
The debit and credit operations are the most "transactional" operations of them all since these mean that you'll be editing two accounts at a time and you want to succeed both editings or fail both at once.
This, again, is a risky business since it involves checking a lot of business rules beginning with having enough money on the account (that is not that simple since having an overdraft account means you can go below zero) all the way to ensuring there is a durable transaction that substracts money from one account and adds money to another one.
Also you must check that a person does not try to transfer negative amounts of money because that will be literally stealing money from other accounts. And the list does not stop here. Scott Hanselman worked in a bank for some time and he might be of some help regarding what needs to be checked.
All in all, my response seems to be a "not worthy" one and you might just as well downvote me but, again, the subject is too deep to be covered in a stackoverflow response.
Sorry.
After watching NDC12 presentation "Crafting Wicked Domain Models" from Jimmy Bogard (http://ndcoslo.oktaset.com/Agenda), I was wandering how to persist that kind of domain model.
This is sample class from presentation:
public class Member
{
List<Offer> _offers;
public Member(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
_offers = new List<Offer>();
}
public string FirstName { get; set; }
public string LastName { get; set; }
public IEnumerable<Offer> AssignedOffers {
get { return _offers; }
}
public int NumberOfOffers { get; private set; }
public Offer AssignOffer(OfferType offerType, IOfferValueCalc valueCalc)
{
var value = valueCalc.CalculateValue(this, offerType);
var expiration = offerType.CalculateExpiration();
var offer = new Offer(this, offerType, expiration, value);
_offers.Add(offer);
NumberOfOffers++;
return offer;
}
}
so there are some rules contained in this domain model:
- Member must have first and last name
- Number of offers can't be changed outside
- Member is responsible for creating new offer, calculating its value and assignment
If if try to map this to some ORM like Entity Framework or NHibernate, it will not work.
So, what's best approach for mapping this kind of model to database with ORM?
For example, how do I load AssignedOffers from DB if there's no setter?
Only thing that does make sense for me is using command/query architecture: queries are always done with DTO as result, not domain entities, and commands are done on domain models. Also, event sourcing is perfect fit for behaviours on domain model. But this kind of CQS architecture isn't maybe suitable for every project, specially brownfield. Or not?
I'm aware of similar questions here, but couldn't find concrete example and solution.
This is actually a very good question and something I have contemplated. It is potentially difficult to create proper domain objects that are fully encapsulated (i.e. no property setters) and use an ORM to build the domain objects directly.
In my experience there are 3 ways of solving this issue:
As already mention by Luka, NHibernate supports mapping to private fields, rather than property setters.
If using EF (which I don't think supports the above) you could use the memento pattern to restore state to your domain objects. e.g. you use entity framework to populate 'memento' objects which your domain entities accept to set their private fields.
As you have pointed out, using CQRS with event sourcing eliminates this problem. This is my preferred method of crafting perfectly encapsulated domain objects, that also have all the added benefits of event sourcing.
Old thread. But there's a more recent post (late 2014) by Vaughn Vernon that addresses just this scenario, with particular reference to Entity Framework. Given that I somehow struggled to find such information, maybe it can be helpful to post it here as well.
Basically the post advocates for the Product domain (aggregate) object to wrap the ProductState EF POCO data object for what concerns the "data bag" side of things. Of course the domain object would still add all its rich domain behaviour through domain-specific methods/accessors, but it would resort to inner data object when it has to get/set its properties.
Copying snippet straight from post:
public class Product
{
public Product(
TenantId tenantId,
ProductId productId,
ProductOwnerId productOwnerId,
string name,
string description)
{
State = new ProductState();
State.ProductKey = tenantId.Id + ":" + productId.Id;
State.ProductOwnerId = productOwnerId;
State.Name = name;
State.Description = description;
State.BacklogItems = new List<ProductBacklogItem>();
}
internal Product(ProductState state)
{
State = state;
}
//...
private readonly ProductState State;
}
public class ProductState
{
[Key]
public string ProductKey { get; set; }
public ProductOwnerId ProductOwnerId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public List<ProductBacklogItemState> BacklogItems { get; set; }
...
}
Repository would use internal constructor in order to instantiate (load) an entity instance from its DB-persisted version.
The one bit I can add myself, is that probably Product domain object should be dirtied with one more accessor just for the purpose of persistence through EF: in the same was as new Product(productState) allows a domain entity to be loaded from database, the opposite way should be allowed through something like:
public class Product
{
// ...
internal ProductState State
{
get
{
// return this.State as is, if you trust the caller (repository),
// or deep clone it and return it
}
}
}
// inside repository.Add(Product product):
dbContext.Add(product.State);
For AssignedOffers : if you look at the code you'll see that AssignedOffers returns value from a field. NHibernate can populate that field like this: Map(x => x.AssignedOffers).Access.Field().
Agree with using CQS.
When doing DDD first thing, you ignore the persistence concerns. THe ORM is tighlty coupled to a RDBMS so it's a persistence concern.
An ORM models persistence structure NOT the domain. Basically the repository must 'convert' the received Aggregate Root to one or many persistence entities. The Bounded Context matters a lot since the Aggregate Root changes according to what are you trying to accomplish as well.
Let's say you want to save the Member in the context of a new offer assigned. Then you'll have something like this (of course this is only one possible scenario)
public interface IAssignOffer
{
int OwnerId {get;}
Offer AssignOffer(OfferType offerType, IOfferValueCalc valueCalc);
IEnumerable<Offer> NewOffers {get; }
}
public class Member:IAssignOffer
{
/* implementation */
}
public interface IDomainRepository
{
void Save(IAssignOffer member);
}
Next the repo will get only the data required in order to change the NH entities and that's all.
About EVent Sourcing, I think that you have to see if it fits your domain and I don't see any problem with using Event Sourcing only for storing domain Aggregate Roots while the rest (mainly infrastructure) can be stored in the ordinary way (relational tables). I think CQRS gives you great flexibility in this matter.