Using a Complex Type in Entity Framework vs. Creating a New Entity

.net .net-4.0 c# entity-framework

Question

Why should I develop a complicated type rather than a new Entity (Table) and a connection between them as I read about the Entity Framework 4.0?

1
29
4/9/2011 7:12:59 PM

Accepted Answer

Address serves as the ideal illustration. It is significantly simpler to manage a complicated type for an address than a new entity. You do not have to deal with the Primary Key when using complicated types. Consider how many typical sorts of entities would have an address when accessing one (Business Units, People, Places). Consider having to create a key for each address after entering the addresses of several persons. With complicated types, all you need to do is get access to the type's internal attributes. Here is a link to an example on MSDN. http://msdn.microsoft.com/en-us/library/bb738613.aspx

19
1/30/2014 8:57:14 PM

Popular Answer

Although this query has been around for some time, I'll nevertheless offer a response in the hopes that the subsequent poor sob will be aware of what to expect.

Complex types do not support lazy loading, at least not in EF 4.3. Consider the address scenario as an illustration. There are 15 columns in your Person database, and 5 of them are addresses for specific people. It has 50,000 records. You create entity Person for the table with a complex type Address.

If you want a list of all the people's names in your database, you would perform

var records = context.Persons;

This pumps 5*50k data into your list without a cause and with an observable lag, which also contains addresses. You might choose to use just the necessary data when loading an anonymous type using

var records = from p in context.Persons
              select new {
                LastName = p.LastName,
                FirstName = p.FirstName,
              }

This is appropriate for this situation, but if you required a list with additional columns—say, let's eight—that weren't addresses, you would either need to add each one as an anonymous type or simply go with the initial scenario and load pointless address data again.

The issue with anonymous types is this: They are quite helpful when used inside a single function, but they compel you to utilize dynamic variables in other parts of your class or class children, which negates some of Visual Studio's refactoring capabilities and exposes you to run-time issues. Ideally, you want to move entities from one technique to another, therefore they should be as light-weight as feasible. Lazy loading is crucial for this reason.

In the aforementioned example, the address data truly has to be in its own table with a full-blown object covering it. As an added bonus, you can easily add a second address for a person to your model if your customer requests one by just including another Address reference in Person.

Contrary to the example above, if you truly want the address information in almost every query you run and are adamant on having those attributes in the Person table, just add them to the Person object. Although you won't have the convenient Address prefix any more, this is not very concerning.

However, there's still more!

The flat terrain of plain EF entities has a hump in the form of complex kinds. It's likely that those in your project won't be able to inherit from your entity base class, which makes it difficult to use methods that deal with your entities in general on them.

Let's say you have an EntityModel entity base class, which specifies a property ID. You may now construct because this is the key for all of your entity objects.

class EntityModelComparer<T> : IEqualityComparer<T> where T : EntityModel

which you can use later to filter duplicates from any IQueryable of type T, where T is an entity class, using Distinct(). Because a complex type lacks an ID field, it cannot inherit from EntityModel, but this is OK because distinct wouldn't be used on it anyway.

Later on, you encounter a circumstance where you need a method of traversing any entity in order to carry out an action. Perhaps you want to dynamically show an entity's attributes on the user interface and allow users to run queries on them. Therefore, you create a class that you can instantiate for a certain type and have it handle everything:

public class GenericModelFilter<T> : where T : EntityModel

Oh bad, your complicated type does not belong to the EntityModel type. To handle complicated types, you must now either make your entity inheritance tree more complex or do rid of the EntityModel contract and limit visibility.

Moving forward, you include a method into your class that, in response to user input, may generate an expression that can be used with Linq to filter any entity class.

Expression<Func<T, bool>> GetPredicate() { ... }

Therefore, you may now do the following:

personFilter = new GenericModelFilter<Person>();
companyFilter = new GenericModelFilter<Company>();
addressFilter = new GenericModelFilter<Address>(); //Complex type for Person

...

var query = from p in context.Persons.Where(personFilter.GetPredicate())
            join c in context.Companies.Where(companyFilter.GetPredicate()) on p.CompanyID = c.ID
            select p;

All entity objects behave in the same way, with the exception of Address, which has unique requirements. It is not possible to join it as you could with Company. You can access it from Person, but how can you apply that Expression to it such that, in the end, you are still in Person? Now that you have to spend a time to sort out this unique situation for a straightforward system that works effortlessly everywhere else.

Throughout the course of a project, this pattern is repeated. Can I say that I have experience? I regret doing so. Complex kinds consistently impede your development without contributing anything meaningful, like a disruptive kid in the back of the classroom. Instead, use things that represent genuine entities in your world.



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow