2

I am having a problem with the Entity Framework code-first approach:

public class Entity
{
    [Key]
    public int Id { get; set; }
    public string A { get; set; }
}

public class Context : DbContext
{
    public DbSet<Entity> Entities { get; set; }
}

Let's say this is the setup for the Entity Framework. It works. I can create an Entity instance and Add it to the Entities set. Now my problem is: I want to create a subclass of Entity that is a ViewModel passed to some view:

public class EntityViewModel : Entity
{
    public String ViewModelProperty { get; set; }
}

Then, when I get back the resulting object from the model binder, I should be able to do this:

public void Action(EntityViewModel vm)
{
    db.Entities.Add(vm); // This should work since EntityViewModel inherits Entity
    db.SaveChanges();
}

Here, I get the following Exception:

Mapping and metadata information could not be found for EntityType 'EntityViewModel'.

I already tried adding the [NotMapped] attribute to EntityViewModel, this doesn't help. If I manually extract the EntityViewModel properties into a new Entity object, it works:

public void Action(EntityViewModel vm)
{
    var entity = new Entity
    {
        Id = vm.Id,
        A = vm.A
    };
    db.Entities.Add(entity); // This works!!!
    db.SaveChanges();
}

Why does the EntityFramework behave this way? Is there a way to tell it to ignore EntityViewModel objects?

Thanks in advance.

devdigital
  • 34,151
  • 9
  • 98
  • 120
Nikon the Third
  • 2,771
  • 24
  • 35

2 Answers2

3

This will not work because EF understands your inheritance as a Table per Hierarchy scheme, so it expects to have the properties of EntityViewModel on the same table as the properties for Entity.

You can use composition to avoid this problem:

public class EntityViewModel : Entity
{
    public Entity Entity { get; set; } 
    public String ViewModelProperty { get; set; }
}

And then

public void Action(EntityViewModel vm)
{
    db.Entities.Add(vm.Entity);
    db.SaveChanges();
}

Check this answer for complex objects model binding rules.

Good luck.

Community
  • 1
  • 1
Anderson Fortaleza
  • 2,449
  • 20
  • 22
1

A better approach would be to use composition rather than inheritence. In this instance, the view model could either expose the model directly to the view, or delegate through to the model.

devdigital
  • 34,151
  • 9
  • 98
  • 120
  • that's until you learn that you have JavaScript code that passes data as the entity type... to make that change means you'll have to change who knows how much JavaScript code. – Clarence Jun 12 '17 at 16:31
  • You shouldn't be sharing types across components - use strict layering for the most agile codebase – devdigital Jun 13 '17 at 08:31
  • lol, in real world programming, you don't have eons of time to develop AND maintain infinite layers of of components just to stay true to SoC, especially if you have a very small project that grew over time.... not everyone's requirements are building a large project from scratch... that's why I like to take each of these Stack overflow issues literally as they're written... advising them to what's correct is of little use to some projects unless we're talking rewrite & good luck convincing management of the ROI of that. Just saying – Clarence Jun 13 '17 at 14:15
  • You're not making much sense - your first comment you are concerned about changes to your data models affecting client side code, but in your last comment you don't want to use strict layering. I suggest you read http://blog.ploeh.dk/2012/02/09/IsLayeringWorththeMapping/ – devdigital Jun 13 '17 at 14:31
  • Veiled insults like "you're not making sense" is not what this forum is for... go to twitter for that. I took Stack Exchange for a more intelligent exchange of ideas by professionals who's at least well versed in the field enough to know how to respond to differing opinions without such retorts. After 25 years in IT and developing a myriad of applications I've seen enough to realize that simply suggesting a change of approach is often the last option available unless there's a rewrite hence my 1st comment. And, if you don't share some types across components, you'll never get anything done. – Clarence Jun 13 '17 at 14:48
  • I had the same problem because I used inheritance to help create a view model to pass back to Ajax call where the client code that exists already uses the entity model I inherited as the object to load data from an html form. I could not change the approach unless I rewrote the entire module and the JavaScript and the access to the form. That was what I inherited, my resolution was to use reflection to create a mapper... took about 20 lines of code & 15 minutes, solved... Entity is not all inclusive and is dumb... there will be times you have to get around its shortcomings and just move on. – Clarence Jun 13 '17 at 14:57
  • I think your use of 'lol' contradicts your desire for a professional conversation, but hopefully I've made it clear of the choices you have between strict layering and the proliferation of types and mapping but an agile codebase vs sharing types and developing a monolith – devdigital Jun 13 '17 at 14:59
  • No, you've made nothing clear except you're insulted by lol. While worth the read, your link doesn't support your point. You should try reading it because under "Further Thoughts" Seemann supports the position that track of Entity to view useful in CRUD apps. Neither Agile codebase or Proliferation of types is a thing but catch phrases like "value added". There's no agile codebase vs sharing types debate and sharing types is in most apps bigger than "Hello World". Mapping is so widely used that AutoMapper is included with Entity scaffold tools and companies have libs just for mapping. – Clarence Jun 13 '17 at 16:34