locked
The entity type 'AllVM' requires a primary key to be defined for VM with EF Core RRS feed

  • Question

  • User991566988 posted

    Hi

    I'm trying to return multiple different non related models in one view as aggregate interface page (each one in html tab) with Entity Framework Core (Core 2.1).

    Holidays model:

        public class Holidays
        {
            public int Id { get; set; }
    
            public string Name{ get; set; }
        }

    Actions model:

        public class Actions
        {
            public int Id { get; set; }
    
            public string Name{ get; set; }
        }

    AllVM model:

        public class AllVM
        {
            public IList<Holidays> Holidays { get; set; }
            public IList<Actions> Actions{ get; set; }
        }

    ApplicationDBContext:

    public virtual DbSet<Actions> Actions { get; set; }
    public virtual DbSet<Holidays> Holidays { get; set; }
    public virtual DbSet<AllVM> AllVM { get; set; }

    Controller:

        public class MyController : Controller
        {
            private readonly ApplicationDbContext _context;
    
            public MyController(ApplicationDbContext context)
            {
                _context = context;
            }
    
            public async Task<IActionResult> AllIndex()
            {
                var all = _context.AllVM.Include(s => s.Holidays).Include(s => s.Actions).AsQueryable();
    
                return View(await all.ToListAsync());
            }

    But this scenario gives me the error:

    InvalidOperationException: The entity type 'AllVM' requires a primary key to be defined.

    I don't want to define a primary key for the ViewModel, I want only to return 2 or more non-related models in AllIndex view each one of them in a tab.

    How please?

    Sunday, April 19, 2020 8:28 AM

Answers

  • User475983607 posted

    The code you shared is invalid.  Plus the code does not follow standards.  "VM" means ViewModel and by definition ViewModels are located in the UI not the data access layer (DbSet). 

    The standard programming is pattern is populating a ViewModel from Entities.  the code would have the following pattern.

    AllVM vm = new AllVM();
    vm.Holidays = _context.Holidays.ToList();
    vm.Actions = _context.Actions.ToList();

    However, even this construct is questionable too.  Usually there is a relationship between Entities which is not expressed in your code or description. Can you explain the programming problem you are trying to solve?

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, April 19, 2020 12:02 PM

All replies

  • User475983607 posted

    The code you shared is invalid.  Plus the code does not follow standards.  "VM" means ViewModel and by definition ViewModels are located in the UI not the data access layer (DbSet). 

    The standard programming is pattern is populating a ViewModel from Entities.  the code would have the following pattern.

    AllVM vm = new AllVM();
    vm.Holidays = _context.Holidays.ToList();
    vm.Actions = _context.Actions.ToList();

    However, even this construct is questionable too.  Usually there is a relationship between Entities which is not expressed in your code or description. Can you explain the programming problem you are trying to solve?

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, April 19, 2020 12:02 PM
  • User1120430333 posted

    You have confused the EF persistence model with a viewmodel. They are two different models with two different purposes. You map data  back and forth between classes and their  properties between the two models.

    https://www.dotnettricks.com/learn/mvc/understanding-viewmodel-in-aspnet-mvc

    Don't confuse the persistence model with the viewmodel.

    https://en.wikipedia.org/wiki/Persistence_framework

    Sunday, April 19, 2020 12:45 PM
  • User-854763662 posted

    Hi musbah7@hotmail.com ,

    For many-to-many relationships configuration in EF core , you need to include an entity class for the join table and mapping two separate one-to-many relationships.

    You can refer to the following example and make modification on yours:

    class MyContext : DbContext
    {
        public DbSet<Post> Posts { get; set; }
        public DbSet<Tag> Tags { get; set; }
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<PostTag>()
                .HasKey(t => new { t.PostId, t.TagId });
    
            modelBuilder.Entity<PostTag>()
                .HasOne(pt => pt.Post)
                .WithMany(p => p.PostTags)
                .HasForeignKey(pt => pt.PostId);
    
            modelBuilder.Entity<PostTag>()
                .HasOne(pt => pt.Tag)
                .WithMany(t => t.PostTags)
                .HasForeignKey(pt => pt.TagId);
        }
    }
    
    public class Post
    {
        public int PostId { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }
    
        public List<PostTag> PostTags { get; set; }
    }
    
    public class Tag
    {
        public string TagId { get; set; }
    
        public List<PostTag> PostTags { get; set; }
    }
    
    public class PostTag
    {
        public int PostId { get; set; }
        public Post Post { get; set; }
    
        public string TagId { get; set; }
        public Tag Tag { get; set; }
    }

    For loading related data , you could refer to this doc.

    Best Regards,

    Sherry

    Tuesday, April 21, 2020 9:46 AM
  • User991566988 posted

    You are right.

    I've removed the VM from the context and did what you suggested.

    Saturday, May 2, 2020 12:03 PM