0

I have a three tier app with a class library as the Infrastructure Layer, which contains an Entity Framework data model (database first).

Entity Framework creates entities under the Model.tt folder. These classes are populated with data from the database.

In the past I would map the classes created by Entity Framework (in the data project) to classes in the Domain project e.g. Infrastructure.dbApplication was mapped to Domain.Application.

My reading is telling me that I should be using the classes contained in .tt as the domain classes i.e. add domain methods to the classes generated by Entity Framework. However, this would mean that the domain classes would be contained in the Infrastructure project, wouldn't it? Is is possible to relocate the classes generated by Entity framework to the Domain project? Am I missing something fundamental here?

w0051977
  • 15,099
  • 32
  • 152
  • 329

3 Answers3

0

You can relocate the entity classes by creating a new item in your Domain project: DbContext EF 6.x Generator (not sure of the name and you might have to install a plugin to get this item in the list, also exists for EF 5.x).

Once you have created this new item, you have to edit it to set the path of your EDMX at the very begining of the file. In my project for example it is:

const string inputFile = @"..\..\DAL.Impl\GlobalSales\Mapping\GlobalSalesContext.edmx";

You will also need to edit the DbContext.tt file to add the right using on top of the generated class. At each change you've done on the EDMX, you also will have to right click the generator and click: "Run custom tool" to generate the new classes.

That being said, is it a good practice? As you can see that's what I have done in my project. As long as you do not have EF specific annotations or stuff like that in the generated entity classes, I would said that it is acceptable.

If you need to change your ORM, you can just keep the generated classes and remove all the EF stuff (.tt files, etc) and the rest of your application will work the same. But that's opinion based.

fharreau
  • 2,105
  • 1
  • 23
  • 46
  • With a code first project it appears that you can map to domain classes much more easily. Do you agree? – w0051977 Aug 04 '17 at 09:16
  • True, you can map to domain much more easily, but be carefull how you do it. If you are doing it using annotation in the entity classes, you will have in your infrastructure project references to EF. And it breaks the separation of concerns principle. If all your mapping is defined within the DbContext class, it is even better than having to add the `EF 6.x Generator`. – fharreau Aug 04 '17 at 09:21
  • If I use Fluent API instead of annotations then I guess this means the domain classes are decoupled i.e. the separation of concerns principle is not broken? – w0051977 Aug 04 '17 at 09:24
  • I am not a code first specialist but if the fluent API means all the mapping done in the DbContext, yes the principle is not broken. As long as you do not add EF references in your Domain project, this is good ^^. Your mapping classes can be in the Domain project while your DbContext can remain in the Infrastructure project. This requires that the Infrastructure project references the Domain project. – fharreau Aug 04 '17 at 09:29
  • I just realized I mis-understood your naming. I fixed it in the answer but not in my olds comments. So your `Infrastructure` project should reference `EF` and contain the `DbContext` with the `fluent mapping`. And the `Domain` project should **not** reference `EF` and contains the `entity classes` (or `domain classes`). – fharreau Aug 04 '17 at 09:34
0

You should move your model to a different project. That is good practice. I don't quite get it what you meant by "moving to to Domain project" Normally entity framework generated classes are used as a domain model. No need for creating "different" domain model from this. This model should be use only near to database operations, whereas web(window) application should use only DTO (Domain transfer objects)

I don't know if you use it or not - but this is a nice tool allowing for recreating model from the database :

https://marketplace.visualstudio.com/items?itemName=SimonHughes.EntityFrameworkReversePOCOGenerator

This allows to store model in classes (instead of EDMX) Someone refers to it as "code first" but there is a misunderstanding. One can use this tool to create model and still be on "database first" This is done simply to omit using EDMX as a model definition.

Piotr
  • 1,155
  • 12
  • 29
  • I have a separate project for the domain and a separate project for the infrastructure. The Entity Framework data model is added to the Infrastructure, however the domain classes exist in the Domain Model. Does that make sense? – w0051977 Aug 04 '17 at 09:27
  • "The Entity Framework data model is added to the Infrastructure, however the domain classes exist in the Domain Model" -> so you have two models? Domain and EF? – Piotr Aug 04 '17 at 09:36
  • Some purist are doing this. The `Entity` classes (mapped from the database) are converted into the `Domain` classes within the `Data Access Layer`. And then converted back during the SaveOrUpdate operation for example. But in my opinion it is really overkill as long as you do not have references to your ORM in your `Entity/Domain/POCO/Whatever` classes. – fharreau Aug 04 '17 at 09:40
  • What is the benefit of the purist approach? I guess if the domain model differs to the data model then it could be beneficial? I guess you don't get this option with the code first approach? – w0051977 Aug 04 '17 at 09:58
  • w0051977, please draw your architecture - as i'm not getting how many models and where you have (in which projects) and you want to achieve :) – Piotr Aug 04 '17 at 10:03
  • @w0051977 Take a look at Andez answer. He explains all very well. Notice that this requires you or your team a good knowledge of how your ORM works (how to attach/dettach entities, how the ORM cache works, etc). This approch can be very usefull when you have differences between your Data Model and your Domain Model. The actual question is: does your situation require such complexity (or will in the future)? – fharreau Aug 04 '17 at 10:08
0

I think in the true sense it is a Data Model - not a Domain Model. Although people talk about having the Entity Framework Model as a domain concept, I don't see how you can easily retro fit Value objects such as say amount which would be represented in the true domain sense as such:

public class CustomerTransaction
{
    public int Id { get; set; }
    public string TransactionNumber { get; set; }
    public Amount Amount { get; set; }
}

public class Amount
{
     public decimal Value { get; }
     public Currency Currency { get; }
}

As opposed to a more incorrect data model approach:

public class CustomerTransaction
{
    public int Id { get; set; }
    public string TransactionNumber { get; set; }
    public int CurrencyType { get; set; }
    public decimal Amount { get; set; }
}

Yes, the example is anaemic, but only interested in properties for clarity sake - not behaviour. You will need to change visibility of properties, whether you need default constructor on the "business/data object" for starters.

So in the domain sense, Amount is a value object on a Customer Transaction - which I am assuming as an entity in the example.

So how would this translate to database mappings via Entity Framework. There might be away to hold the above in a single CustomerTransaction table as the flat structure in the data model, but my way would to be add an additional repository around it and map out to the data structures.

Udi Dahan has some good information on DDD and ORM in the true sense. I thought somewhere he talked about DDD and ORM having the Data Model instance as a private field in the domain object but I might be wrong.

Also, that data model suffers from Primitive Obsession (I think Fowler coined it in his Refactoring book - although it Is in his book) Jimmy Bogard talks about that here.

Check out Udi Dahan stuff.

Andez
  • 5,588
  • 20
  • 75
  • 116
  • This is a very good approach, fully decoupled, but not always required. When there is no differences between your Domain-Model and your Data-Model (which is in my experience most of the time the case), it is really overkill. – fharreau Aug 04 '17 at 09:45
  • Very true... But nothing starts off that way. Its the quickest root to market or to customer. I wrote my first Entity Framework based solution like that - single DB Context used all over a WinForms application. One big unbounded context - it ended up a big ball of mud and hard to change. Repeated logic scattered all over. But it was really quick to get up and running. Having thought about retro fitting what I know now, bounded context and domain model were required. – Andez Aug 04 '17 at 09:50
  • 1
    I can't argue against that. It is absolutely true and it is the best way to go ^^. But it depends of the project: How will it grow? What is the maturity of the team regarding to the ORM? Most of my (modest - I work in a software and computing services company that does not target complex customer ^^) projects does not require this kind of abstraction. An most of my co-worker do not have the knowledge to maintain such code. – fharreau Aug 04 '17 at 10:13
  • Thanks for the link. It was helpful. Are you saying that there should be separate classes? e.g. two customer classes (one for database and the other for domain). – w0051977 Aug 07 '17 at 11:05
  • 1
    I am not saying there SHOULD. I guess depends on the case like @fharreau said. From my experience, it all depends on how you implement your domain model. If you have more business orientated value objects like the Amount in the example, I've never seen a way to do it, so I use separate domain v data models. I will test a few things out when I get time just to see if you can do such mappings. I cant remember if Julie Lerman ever covered such topics. – Andez Aug 07 '17 at 14:47
  • If your business model is equivalent to your data model (one to one mapping), there is no need to define each entity twice. Unless if one of them is going to change a lot in the future (you may want to keep stability on one model for example). – fharreau Aug 08 '17 at 08:07
  • I just ran into the case. In the first place, the purchase costs of my articles were stored into the database. DataModel and DomainModel were the same classes. But a for the sake of my clients, I now have to store the purchase costs in another datastore. My DomainModel still have the purchase cost but not my DataModel anymore. I have to change some things in the whole program instead of just updating my mapping in my DAL. – fharreau Aug 17 '17 at 13:55
  • Shame I cannot update the answer. I came across the following article from this mornings Morning Brew. It talks about a richer domain model and using it along with Entity Framework. Given that, nugget of information, I hope it changes my opinion - and reduces all of this hideous boiler plate code needed in future. Safe to say I haven't given it a go as yet, but worth a read. https://www.devtrends.co.uk/blog/3-ways-to-avoid-an-anemic-domain-model-in-ef-core – Andez Oct 13 '17 at 08:22
  • Additionally had a play with EF Core 2.1 Preview and you can now set a public getter with a private readonly backing field - so my views might be changing. As long as we can hydrate complex objects I will be over the moon! – Andez Feb 21 '18 at 13:50