2

Say you have the following entity that represent an exact resource from a table, we're talking .NET Core with Entity Framework Core, code-first approach.

public class Person 
{
    [Key]
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Generally speaking when returning DTOs from this class I might decide to just return one field called FullName where I would join first and last name, but rather than duplicating that logic around, how bad of an idea is to just declare a method on Person?

public string GetFullName() 
{
    return $"{FirstName} {LastName}";
}
0
3

In my view this is the intention of code first EF. That you dont have DTOs you simply persist your business objects by magic.

Unfortunately I don't think it works very well. For example if instead of a method you were to add a FullName calculated property you would then have to add more EF attributes to tell it how to handle that property.

Adding attributes tightly couples the object to the datalayer and half a tonne of EF dlls.

The 'best practice' way to use EF is to hide it behind a repository class. However this negates most if not all of its benefits.

EF is the VB6 print preview of databases. You can do DB persistance with a couple of clicks, but once you get to more complex cases its easier to do it yourself from scratch

9
  • I think EF is properly understood as a technology which enables a division of labour. If you have 500 people working on an application, then you have a few EF experts who are there to tackle the interface with the database, which are not the same people as the database designers nor the same as the client-side programmers. I think why most programmers end up scratching their heads with EF (and I'm one example), is because they don't work on the scale where that division of labour exists. – Steve Apr 11 '20 at 11:40
  • seems to me like you have invented an unneeded 3rd set of people. Just don't use EF – Ewan Apr 11 '20 at 12:05
  • exactly. For small teams of generalists, the thing is just another complication. It's only when you're marshalling hundreds or thousands of people in a single firm, many of whom will be second-rate in capability and experience, that having such specialists on the payroll makes sense. – Steve Apr 11 '20 at 12:50
  • 1
    @Ewan: "It's easier to do your own DataLayer" What? That is patently absurd. I'm not saying EF is perfect in every scenario (just like any library, its applicability is contextual), but it is in no way easier to roll your own data layer from scratch. Both the data mapping between database and codebase and resolving relationships between entities is massively simplified by using an ORM like EF (among others). – Flater Apr 11 '20 at 14:27
  • 1
    Datalayer code is the simplest code in any project. Its just boilerplate, but writing it yourself means you avoid 'fighting the system' when you need you do something non standard. I Always advise using the basic sqlclient over EF especialy for novice programmers – Ewan Apr 11 '20 at 15:45
2

It depends on the layering of your application, and if you think your application requires a business layer which is not tied to a specific ORM technology, or if you think such a layer separation is not necessary.

Usually, you decide to have either one layer, where your "business objects" are directly mapped to database tables and contain certain business logic (like a method GetFullName). This is probably sufficient for smaller applications with only a few tables, a few business classes, and not many structural differences between them.

Or, you decide to have two layers, with a full separation between a class PersonDTO which is used for the EF code-first approach of persistence, and a business class Person, which is independent from EF, but holds the business logic. In this case, Person will get a method like GetFullName and providing the same logic in PersonDTO would duplicate it, which is actually what you asked us how to avoid.

I guess it is clear this is a trade-off - the former approach requires less code, but every code which uses your business objects now requires to have dependency on EF as well, and it imposes certain restrictions on how your business classes will have to look like. The latter requires extra code for mapping between PersonDTO and Person (this is where tools like Automapper show their value).

So I recommend you first look what kind of application you are going to write, and if you think the layer separation between DTOs and a business layer makes sense or not. Then you know where to place the methods.

1

In my opinion its better to always project your entities before sending them off to the consumer. There are some ways you can reuse your projection. The most straight forward way is to use extension methods.

internal static class PersonExtensions
{
   public static IQueryable<PersonInfo> Project(this IQueryable<Person> source) 
   {
      return source.Select(p => new PersonInfo { ... }
   }
}

You can also reuse the Expression used from teh Project select. And in EF Core yuo can even use the expression as part of another expression which is pretty cool, but it has the downside of that you need to explicit include navigation properties, something that is automatically resolved when using normal expressions.

private static readonly Expression<Func<Person, PersonInfo>> Projection = p => new PersonInfo { ... };
private static Func<Person, PersonInfo> CompiledProjection = Projection.Compile();

Then it could be used like for example

   .source
   .Include(p => p.navProp)
   .Select(p => new 
   {
      dto = Compiled.Invoke(p),
      children = p.Children.AsQueryable().Select(Projection)
   }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.