I am looking to setup architecture for entity framework that will break apart the entities into multiple models. What I am wondering if it is possible to code-generate one set of entities, so that each model uses the same set of data access classes? I realize the issue with contexts, but I was wondering if each context really needed to have its own set of classes, or I can create many contexts but only have one set of classes that represent the backend tables, using the self-tracking entities generation feature.
Thanks.
You can definitely share POCO classes across multiple models.
For example a class like this:
public class Person
{
public int ID {get;set;}
public string Firstname {get;set;}
public string Surname {get;set;}
public string Lastname {get {return Surname;} set {Surname = value;}}
}
Would work in an EDMX that defines Person as ID,Firstname,Surname
And would work in a second EDMX that defines Person as ID,Firstname,Lastname
Not sure though about Self-Tracking Entities, STEs are 'POCO' but they also have some model specific code which might break if the definition of the EntityType is different in your two EDMXs (like in my above sample).
You'd have to try it out.
Hope this helps
Alex (Former EF team member)
Related
This question already has answers here:
Should Entities in Domain Driven Design and Entity Framework be the same?
(4 answers)
Closed 5 years ago.
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?
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.
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.
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.
I am little bit confused about the problem. I have an entity Product that is represented in the database. It looks like POCO. Here is example (I use attributes instead of fluent api for simplicity).
public class Product
{
[Key]
public int Id { get; set; }
//other properties that have mapping to db
}
But now I want to avoid AnemicDomainModel anti-pattern
So I am going to fill the Product model with methods and properties, that do not have mapping to db, so I should use [Ignore].
public class Product
{
[Key]
public int Id { get; set; }
[Ignore]
public object FooProperty { get; set; }
//other properties that have mapping to db
//other properties and methods that do not have mapping to db
}
I think such a way spoils my model. In this article I've found acceptable workaround. Its idea is to separate Product (domain model) and ProductState (state of product that is stored in the database). So Product is wrapper for ProductState.
I really want to know the views of other developers. Thanks a lot for your answers.
I understood that my real question sounds something like that: "Should I separate Data model and domain model? Can I change EF entities from Anemic to Rich?"
To ensure persistence ignorance of your entities, I've found EF Fluent Mapping to be better than Data Annotations. The mappings are declared in an external file, thus normally your entity doesn't have to change if something in the persistence layer changes. However, there are still some things you can't map with EF.
Vaughn's "backing state object" solution you linked to is nice, but it is an extra layer of indirection which adds a fair amount of complexity to your application. It's a matter of personal taste, but I would use it only in cases when you absolutely need stuff in your entities that cannot be mapped directly because of EF shortcomings. It also plays well with an Event Sourcing approach.
The beauty of the Entity Framework is that it allows you to map your database tables to your domain model using mappings which can be defined using the Fluent API, therefore there is no need to have separate data entities. This is in comparison to its predecessor Linq To SQL where you'd map each table to an individual data entity.
Take the following example, for the paradigm of a Student and Course - a student can take many courses, and a course can have many students, therefore a many-to-many relationship in your database design. This would consist of three tables: Student, Course, StudentToCourse.
The EF will allow you to use Fluent API mappings to create the many collections on either side of the relationship without having the intermediate table (StudentToCourse) defined in your model (StudentToCourse has no existence in a DOMAIN MODEL), you would only need two classes in your domain, Student and Course. Whereas in LinqToSQL you'd have to define all three in your model as data entities and then create mappings between your data entities and domain model resulting in lots of plumbing work open to bugs.
The argument of the anaemic vs rich domain model should have little effect on your mapping between your model and database tables, but focuses on where you place the behaviour - in either the domain model or the service layer.
Right now I am learning a lot about the Entity Framework from Videos on Pluralsight, so excuse my Question which might look newbish but I can not understand what Complex Types are or why I would need them.
I do know that I have to map them via Annotations or Fluent Api something like this:
modelBuilder.ComplexType<blubb>();
Maybe someone could elaborate the need of Complex Types for me?
Assume you have an entity for Courses in a class, that entity has scalar properties of Location, Days and Time, but you find you want to abstract that so that other entities can use the same model. So you can create a complex type that contains Days, Location and Time give it a name: ComplexType1. Now other entities can use this type rather than individual scalar properties just by declaring ComplexType1 in the model definition.
Complex Types are repeating structural patterns in your database. You have to custom map them because there is no way for it to be inferred.
An example would be two tables that both have address related columns:
Company
CompanyName
AddressLine1
AddressLine2
Postcode
Account Manager
Name
TelephoneNumber
SuperiorName
AddressLine1
AddressLine2
Postcode
This is obviously not well-normalized database design but such situations do occur. You can abstract the model for address into a complex type, then specify that both Company and AccountManager have that complex type rather than keep mapping the matching (albeit separate in the database) columns for each table that has address columns.
Here's an in depth article on Complex Types: http://msdn.microsoft.com/en-gb/data/jj680147.aspx
And here is one that isn't quite so heavy, and shows the benefit of mapping two addresses on one model, things like that: http://visualstudiomagazine.com/articles/2014/04/01/making-complex-types-useful.aspx
Complex type are types that don't map to a table like entities instead they map to one or more fields.
The following complex type
public class Descriptor
{
public string Name {get;set;}
public string Description {get;set;}
}
And entity
public class MyEntity
{
public Descriptor { get;set;}
}
This would map to a table with Name and Description fields. It is a useful way to have a type encapsulate a common set of fields/properties you might want on several entities.
I have some POCO classes which can generally divided into two groups, for example:
public class Student
{
public Student()
{
this.Courses = new List<Course>();
this.Clubs = new List<Club>();
}
public int Id { get; set; }
public virtual ICollection<Course> Courses { get; set; }
public virtual ICollection<Club> Clubs { get; set; }
}
and corresponding Course and Club classes, and they all have their own relationships to other classes.
The problem is, those two groups are big, they both contains a lot of classes, and each of them is a working unit, like student courses management unit which will provide functions for anything related to course; and club management unit which will provide functions. So I am not planning to put them together into one DbContext.
There are some requirements that will need to get a student from club then retrieve its course information. What I am doing now, is do another query in course unit by using the student Id I got from club unit. Which works fine but I hopping to make it simpler, like
foreach(var student in club.Students){
ClubContext.Detach(student);
CourseContext.Attach(student);
foreach(var c in student.Courses){
...
}
}
but I got some exception like this:
There is already a generated proxy type for the object layer type
'POCOTest.Models.Student'. This occurs when the same object layer
type is mapped by two or more different models in an AppDomain.
Is this possible? and if so, how? Thanks~
You can have single class mapped in multiple contexts but the mapping should be always the same. If it is not the same you cannot use dynamic proxies (lazy loading) because each mapping demands its own proxy type handling its navigation properties.
In your case the first context mapping contains Student entity with relation to Club but this relation doesn't exist in the second mapping where in contrary relation with Course exists. That demands two different proxy types for the same entity type.
The exception says that it is not supported. There are two reasons why this cannot work:
EF stores proxy types in static dictionary where each entity type can have only single generated proxy
Even if you fix the first point (by downloading source codes and modifying them) you will still not be able to do what you want because proxy type is the entity. It is not a wrapper. So the type cannot be replaced when you detach it from the first context and attach to second one.
If you don't need lazy loading, just remove the "virtual" keyword from your navigation properties and it will work as you want. Virtual is used to enable Lazy Loading.
Let's say I have 'Customer' table in SQL DB and I'm using Entity Framework.
Now, for instance, in Controller or ViewModel I retrieve the customer by var customer = Page.Current.Customer when it's code is:
public class Page
{
...
// Customer is EntityObject that created by Entity Framework
public Customer Customer
{
get
{
return (new ContextEntity()).Customers.First();
}
}
}
My question:
Should I refer to Entity Object class(Customer) as DAL and create CustomerWrapper or I can use it in other code of my application?
I mean, is it correct that Page.Current.Customer will return Customer Entity or I should use Customer Entity as DAL and Page.Current.Customer should return custom Customer, some kind of CustomWrapper?
In one hand if will decided to change Customer table name to site_Customer(in SQL DB) I'll refresh the EntityModel and will only change the code in the Page class to
public class Page
{
...
// Customer is EntityObject that created by Entity Framework
public Customer Customer
{
get
{
return (new ContextEntity()).site_Customers.First();
}
}
}
But in the other hand I'll have Customer Entity + WrapperCustomer
What is better?
All class in an EDMX file are partial classes. This means that you can extend these classes by creating a new Class file.
For example...
public partial class Customer
{
// Here are the methods, properties, relationships created by EDMX Wizard.
}
In another area of your project, I usually put it in the same location as the EDMX, you can add a new Class file that has the same signature.
public partial class Customer
{
// Here are the methods, properties, etc. created by you.
}
When the project is compiled these two classes will become one class in the compiled code. Now, when you change your EDMX, yes it should map correctly, but this is not always the case as EF has be known to be very buggy (suppose to be fixed with EF 4.1 in MVC 3), you can simply change the class name to match whatever it is in the EDMX and "Voila!" you have transferred all custom added code for the class to the new entity object. This is essentially your "class wrapper".
That all depends on the level of abstraction you want to use in your application and needs of presentation layer. Both approaches are possible.
Your code is probably already tightly coupled to Entity Framework (EntityObject is EF type) and it is also not very well testable (Page.Current is probably static) so discussion about some more advanced architecture approaches and separation of concerns is not needed.
Few observations from your code:
Context is Disposable!!!
Renaming anything in your database should not modify your class names. That is the responsibility of EF mapping (EDMX) to correctly map entities to new database names.
If you want to use WCF, then you will probably need to create clear POCOs to avoid a lot of issues.
If you want your controllers/viewmodels/pages/whatever to be unit testable, then you will need to abstract your EntityContext in repository interfaces+classes (see repository pattern).
If you just want to make a quick and simple non-testable application, then you don't need to bother about it. Don't forget to dispose the data context at the end of each request.