1

I have 2 entities Movie and MovieVersion who inherits the following abstract class, defining an ID property:

public interface IEntity
{
    int Id { get; }
}

public abstract class EntityBase : IEntity
{
    public int Id { get; set; }
}

public class Movie : EntityBase, IAggregateRoot ...

public class MovieVersion : EntityBase ...

I have setup the following configuration:

public class MovieConfiguration : IEntityTypeConfiguration<Movie>
{
    public void Configure(EntityTypeBuilder<Movie> builder)
    {
        builder.HasKey(m => m.Id);

        builder.Property(m => m.Id).ValueGeneratedOnAdd();

        builder.HasMany(m => m.MovieVersions)
            .WithOne();
    }
}

public class MovieVersionConfiguration : IEntityTypeConfiguration<MovieVersion>
{
    public void Configure(EntityTypeBuilder<MovieVersion> builder)
    {
        builder.HasKey(m => m.Id);

        builder.Property(m => m.Id).ValueGeneratedOnAdd();
    }
}

I try to seed with this code:

var movieRepository = new MovieRepository(context);
var movie = new Movie("The Good, the Bad and the Ugly", 1966);
movieRepository.AddMovie(movie);

And I get this error: "Value cannot be null. (Parameter 'key')". What can have gone wrong? I thought that I had it working before, but now something has changed. I'm on EF Core v3.1.1 and using SQLite.

For completeness, here is an excerpt from repository:

public abstract class RepositoryBase<T> where T : class, IAggregateRoot
{
    private readonly ApplicationDbContext _context;

    public RepositoryBase(ApplicationDbContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }

    protected DbSet<T> Set => _context.Set<T>();
}

public class MovieRepository : RepositoryBase<Movie>, IMovieRepository
{
    public MovieRepository(ApplicationDbContext context) : base(context) {}

    public void AddMovie(Movie movie)
    {
        Set.Add(movie);
    }
}

DbContext:

public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    public DbSet<Movie> Movies { get; set; }

    public DbSet<MovieVersion> MovieVersions { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());

        base.OnModelCreating(builder);
    }
}

Seed:

context.Database.EnsureCreated();

if (context.Movies.Any()) return;

var movieRepository = new MovieRepository(context);
var movieContainerRepository = new MovieContainerRepository(context);

var movie = new Movie("The Good, the Bad and the Ugly", 1966);
movieRepository.AddMovie(movie); // throws mentioned error

Thank you in advance!

Viktor
  • 487
  • 2
  • 8
  • 26
  • Does the configuration applied correctly?Refer to [here](https://stackoverflow.com/questions/58158441/value-cannot-be-null-parameter-key-in-asp-net-core-3-0).Or you could refer to this [Use IEntityTypeConfiguration with a base entity](https://stackoverflow.com/questions/46978332/use-ientitytypeconfiguration-with-a-base-entity) – Ryan Feb 13 '20 at 03:31
  • 1. Did you add your DbSet? 2.I don't know what IEntity is doing there 3.you can also inherit off a non-abstract EntityBase class if all you are doing is adding an Id to each one. – Jeff Feb 13 '20 at 04:17
  • @JeffLi 1. Forgot to show the DbContext, but yes, I have added the DbSets as properties.2. IEntity only specifies the ID property. 3. How would that help me? – Viktor Feb 13 '20 at 08:54
  • @XingZou Yes, I use extension ApplyConfigurationsFromAssembly(). – Viktor Feb 13 '20 at 08:55
  • Added some missing code now. – Viktor Feb 13 '20 at 09:00
  • have you tried to put `base.OnModelCreating(builder);` at the beginning of the `OnModelCreating`? – Ryan Feb 14 '20 at 01:52
  • @XingZou Did not fix it, sorry. – Viktor Apr 20 '20 at 23:35
  • How is `Movie`'s id being generated? Is it an auto-increment field in DB? And what about the foreign key constraint Id? How are you assigning `MovieVersion`'s Id? – Hooman Bahreini Apr 21 '20 at 01:37
  • I couldnot reproduce the issue, I created sample console app without Repository Pattern and I am not getting the exception using the same TEntity and IEntityTypeConfiguration can you share the startup class and from where you are seeding – vrs Apr 21 '20 at 03:17
  • also use Debug /Console Logger and produce ef db command, transaction and change tracking logs – vrs Apr 21 '20 at 03:19
  • @HoomanBahreini ID should be generated by SQLite database. DB is created from the C# configuration. Same thing for `MovieVersion`. – Viktor Apr 25 '20 at 10:45
  • @vrs Added seed code. Main program just calls the seed before creating host. – Viktor Apr 25 '20 at 10:52
  • Did you check that autoincrements have been correctly set on the SQLite tables? Try to do an insert without specifying the Id, and check that it creates a new tuple. – Alessandro R Apr 27 '20 at 12:05

2 Answers2

0

Your entity interface does not have a setter , maybe you should think to change it like this

public interface IEntity
{
    int Id { get; set;}
}
Houssem
  • 1,042
  • 7
  • 16
0

I think you are using sql lite which does not have identity column. It is AUTOINCREMENT in sql lite use right Framework To use SQLite database provider, the first step is to install Microsoft.EntityFrameworkCore.Sqlite NuGet package.

OR do manual way of correcting table EF looks for DB and create identity column in SQL syntax. Remove you data Migration. Try changing your table like this.

CREATE TABLE COMPANY(
   ID INTEGER PRIMARY KEY AUTOINCREMENT,
   NAME           TEXT      NOT NULL,
   AGE            INT       NOT NULL,
   ADDRESS        CHAR(50),
   SALARY         REAL
);
Jin Thakur
  • 2,711
  • 18
  • 15