efcore icon indicating copy to clipboard operation
efcore copied to clipboard

Cannot create a DbSet because this type is not included in the model for the context

Open AleksaRistic216 opened this issue 1 year ago • 0 comments

EF Core version: 8.0.6 Database provider: Postgres Target framework: .NET 8.0 Operating system: Linux Debian 12 IDE: JetBrains Rider

=== Description

Updating EF Core version from 7.0.20 to 8.0.6 I encountered the error where DbSet<T>.Update() stopped working for multi level include.

It drops the error:

Cannot create a DbSet for 'IIncludableQueryable<OrderItemEntity, ProductPriceEntity>' because this type is not included in the model for the context.
      System.InvalidOperationException: Cannot create a DbSet for 'IIncludableQueryable<OrderItemEntity, ProductPriceEntity>' because this type is not included in the model for the context.
         at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityType()
         at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.EntryWithoutDetectChanges(TEntity entity)
         at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.Update(TEntity entity)
         at LSCore.Domain.Managers.LSCoreManagerBase`1.Update[TEntity](TEntity entity)

=== Code and configuration used

Part of the code that drops the error:

        var orderItems = dbContext.Set<OrderItemEntity>().AsQueryable()
            .Where(x =>
                x.IsActive &&
                x.OrderId == request!.Id)
            .Include(x => x.Product)
            .ThenInclude(x => x.Price);

        if (!orderItems.Any())
            return;
        if(request.UserId == null)
            CalculateAndApplyOneTimePrices();
        else
            CalculateAndApplyUserPrices();

        dbContext.Set<OrderItemEntity>().Update(orderItems);
        dbContext.SaveChanges(); // This part trows the error
using TD.Web.Common.Repository.DbMappings;
using TD.Web.Common.Contracts.Entities;
using Microsoft.EntityFrameworkCore;
using LSCore.Repository;

namespace TD.Web.Common.Repository;

public class WebDbContext(DbContextOptions<WebDbContext> options) : LSCoreDbContext<WebDbContext>(options)
{
    public DbSet<UnitEntity> Units { get; set; }
    public DbSet<UserEntity> Users { get; set; }
    public DbSet<CityEntity> Cities { get; set; }
    public DbSet<OrderEntity> Orders { get; set; }
    public DbSet<StoreEntity> Stores { get; set; }
    public DbSet<ProductEntity> Products { get; set; }
    public DbSet<SettingEntity> Settings { get; set; }
    public DbSet<OrderItemEntity> OrderItems { get; set; }
    public DbSet<ProfessionEntity> Professions { get; set; }
    public DbSet<GlobalAlertEntity> GlobalAlerts { get; set; }
    public DbSet<PaymentTypeEntity> PaymentTypes { get; set; }
    public DbSet<ProductGroupEntity> ProductGroups { get; set; }
    public DbSet<ProductPriceEntity> ProductPrices { get; set; }
    public DbSet<StatisticsItemEntity> StatisticsItems { get; set; }
    public DbSet<ProductPriceGroupEntity> ProductPriceGroups { get; set; }
    public DbSet<ProductPriceGroupLevelEntity> ProductPriceGroupLevel { get; set; }
    public DbSet<OrderOneTimeInformationEntity> OrderOneTimeInformation { get; set; }
    public DbSet<KomercijalnoWebProductLinkEntity> KomercijalnoWebProductLinks { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<UnitEntity>().AddMap(new UnitEntityMap());
        modelBuilder.Entity<CityEntity>().AddMap(new CityEntityMap());
        modelBuilder.Entity<UserEntity>().AddMap(new UserEntityMap());
        modelBuilder.Entity<OrderEntity>().AddMap(new OrderEntityMap());
        modelBuilder.Entity<StoreEntity>().AddMap(new StoreEntityMap());
        modelBuilder.Entity<SettingEntity>().AddMap(new SettingEntityMap());
        modelBuilder.Entity<ProductEntity>().AddMap(new ProductEntityMap());
        modelBuilder.Entity<OrderItemEntity>().AddMap(new OrderItemEntityMap());
        modelBuilder.Entity<ProfessionEntity>().AddMap(new ProfessionEntityMap());
        modelBuilder.Entity<GlobalAlertEntity>().AddMap(new GlobalAlertEntityMap());
        modelBuilder.Entity<PaymentTypeEntity>().AddMap(new PaymentTypeEntityMap());
        modelBuilder.Entity<ProductGroupEntity>().AddMap(new ProductGroupEntityMap());
        modelBuilder.Entity<ProductPriceEntity>().AddMap(new ProductPriceEntityMap());
        modelBuilder.Entity<StatisticsItemEntity>().AddMap(new StatisticsItemEntityMap());
        modelBuilder.Entity<ProductPriceGroupEntity>().AddMap(new ProductPriceGroupEntityMap());
        modelBuilder.Entity<ProductPriceGroupLevelEntity>().AddMap(new ProductPriceGroupLevelEntityMap());
        modelBuilder.Entity<OrderOneTimeInformationEntity>().AddMap(new OrderOneTimeInformationEntityMap());
        modelBuilder.Entity<KomercijalnoWebProductLinkEntity>().AddMap(new KomercijalnoWebProductLinkEntityMap());
    }
}

// LSCoreDbContext
namespace LSCore.Repository
{
  public abstract class LSCoreDbContext<TContext> : DbContext, ILSCoreDbContext where TContext : DbContext
  {
    protected LSCoreDbContext(DbContextOptions<TContext> options)
      : base((DbContextOptions) options)
    {
    }
  }
}

And the mapper:

    public class OrderItemEntityMap : LSCoreEntityMap<OrderItemEntity>
    {
        public override Action<EntityTypeBuilder<OrderItemEntity>> Mapper { get; } = entityTypeBuilder =>
        {
            entityTypeBuilder
                .HasOne(x => x.Order)
                .WithMany(x => x.Items)
                .HasForeignKey(x => x.OrderId);

            entityTypeBuilder
                .HasOne(x => x.Product)
                .WithMany()
                .HasForeignKey(x => x.ProductId);

            entityTypeBuilder
                .Property(x => x.Price)
                .IsRequired();

            entityTypeBuilder
                .Property(x => x.Quantity)
                .IsRequired();

            entityTypeBuilder
                .Property(x => x.PriceWithoutDiscount)
                .IsRequired();
        };
    }

// LSCore entity map
namespace LSCore.Repository
{
  public abstract class LSCoreEntityMap<TEntity> : ILSCoreEntityMap<TEntity> where TEntity : class, ILSCoreEntity
  {
    private bool _suppressDefaultMapping { get; set; }

    public abstract Action<EntityTypeBuilder<TEntity>> Mapper { get; }

    protected LSCoreEntityMap()
    {
    }

    protected LSCoreEntityMap(bool suppressDefaultMapping)
    {
      this._suppressDefaultMapping = suppressDefaultMapping;
    }

    public EntityTypeBuilder<TEntity> Map(EntityTypeBuilder<TEntity> entityTypeBuilder)
    {
      if (!this._suppressDefaultMapping)
        this.MapDefaultFields(entityTypeBuilder);
      this.Mapper(entityTypeBuilder);
      return entityTypeBuilder;
    }

    private void MapDefaultFields(EntityTypeBuilder<TEntity> entityTypeBuilder)
    {
      entityTypeBuilder.HasKey((Expression<Func<TEntity, object>>) (x => (object) x.Id));
      entityTypeBuilder.Property<DateTime>((Expression<Func<TEntity, DateTime>>) (x => x.CreatedAt)).IsRequired(true);
      entityTypeBuilder.Property<bool>((Expression<Func<TEntity, bool>>) (x => x.IsActive)).HasDefaultValue<bool>((object) true).IsRequired(true);
      entityTypeBuilder.Property<DateTime?>((Expression<Func<TEntity, DateTime?>>) (x => x.UpdatedAt)).IsRequired(false);
      entityTypeBuilder.Property<long?>((Expression<Func<TEntity, long?>>) (x => x.UpdatedBy)).IsRequired(false);
      foreach (PropertyInfo property in typeof (TEntity).GetProperties())
      {
        if (property.PropertyType == typeof (DateTime))
          entityTypeBuilder.Property(property.PropertyType, property.Name).HasColumnType("timestamp");
      }
    }
  }
}

=== Debugging info

Strange thing I encountered while debugging is that select does enumerate everything as it should (indicating that dbSet is there and mapping works) but only save changes makes mistake.

EntityFrameworkCoreCannotCreateDbSet

AleksaRistic216 avatar Jun 22 '24 06:06 AleksaRistic216