How to fix "The seed entity for entity type 'X cannot be added because there was no value provided" when the value is actually provided?

asp.net-core asp.net-mvc c# entity-framework-core

Question

I've been having a problem with testing my app because of this error, mroe specifically The seed entity for entity type 'Artikal' cannot be added because there was no value provided. The problem is that the value (that represents a FK in Artikal class) is definitely provided, both through the dictionary paroviTip and the class Tip itself. I want to seed some data into a database, using the modelBuilder extension (that should be the proper way for .NET Core 2.2), but the migration can't be added because of this particular error.

I pretty much ran out of options so I need an outside look on this code.

ModelBuilderExtensions that fills the DB:

using BestDeal.Models;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using System;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace BestDeal.AdapteriPodataka
{
    public static class ModelBuilderExtensions
    {
        public static void PopuniBazu(this ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Artikal>().HasData
                    (
                  new Artikal
                  {
                      NazivArtikla = "HP 250 G6",
                      CijenaArtikla = 700,
                      IdArtikla = 1,
                      KratkiOpis = "Vrhunski laptop za prosječnog korisnika!",
                      DetaljniOpis = "Povežite se sa cijenjenim HP 250 notebook računarima. Završajite poslovne zadatke sa Intel® tehnologijom, osnovnim alatima za saradnju koji su učitani na HP 250. Izdržljiva šasija pomaže zaštiti laptopa od strogosti dana.",
                      URLMaleSlike1 = "https://static.toiimg.com/photo/60104728/HP-15-BS542TU-2EY84PA-Laptop-Core-i3-6th-Gen4-GB1-TBDOS.jpg",
                      URLSlike1 = "https://images-na.ssl-images-amazon.com/images/I/81iq991JMEL._SL1500_.jpg",
                      TipArtikla = ParoviTip["Laptopi"],
                      tipNaziv = "Laptopi"
                  }/*There is 30 of these, shortened for easier overview*/  
                    );

        }
              private static Dictionary<string, Tip> paroviTip = new Dictionary<string, Tip>();
        public static Dictionary<string, Tip> ParoviTip
        {
            get
            {
                if (paroviTip.Count==0)
                {
                    var listaTipova = new Tip[]
                    {
                    new Tip { Ime = "Laptopi", idTipa = 1 },
                    new Tip { Ime = "Mobiteli", idTipa = 2 },
                    new Tip { Ime = "Računari", idTipa = 3 },
                    new Tip { Ime = "Računarska oprema", idTipa = 4 }
                    };
                    foreach (Tip tipcic in listaTipova)
                    {
                        paroviTip.Add(tipcic.Ime, tipcic);
                    }
                }

                return paroviTip;
            }
        }
        }
    }

Context file:

using BestDeal.AdapteriPodataka;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace BestDeal.Models
{
    //TODO: Skontati koji context ide, identitymodel, No authorization problem
    // You can add profile data for the user by adding more properties to your IdentityUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.

    //IdentityDbContext<IdentityUser> ???
    public class BestDealContext : IdentityDbContext<IdentityUser>
    {

        //automatske migracije
        private static readonly bool[] _migrated = { false };

        public BestDealContext(DbContextOptions<BestDealContext> options) : base(options)
        {
            /*  if (!_migrated[0])
                  lock (_migrated)
                      if (!_migrated[0])
                      {
                          Database.Migrate(); // apply all migrations
                          _migrated[0] = true;
                      }*/
           // Database.ExecuteSqlCommand("SET IDENTITY_INSERT Artikal ON");
        }
        public DbSet<IdentityUser> IdentityUser { get; set; }

        public DbSet<KorpaInfo> KorpaInfo { get; set; }
        public DbSet<Narudzba> Narudzba { get; set; }
        public DbSet<Obavijest> Obavijest { get; set; }
        public DbSet<ChatObavijest> ChatObavijest { get; set; }
        public DbSet<NarudzbeObavijest> NarudzbeObavijest { get; set; }
        public DbSet<Recenzija> Recenzija { get; set; }
       // public DbSet<StanjeNarudzbe> StanjeNarudzbe { get; set; }
        public DbSet<Tip> Tip { get; set; }
      //  public DbSet<Tipovi> Tipovi { get; set; }
        public DbSet<Artikal> Artikal { get; set; }
       public DbSet<Korpa> Korpa { get; set; }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<IdentityUser>().ToTable("IdentityUsers");
            modelBuilder.Entity<Korpa>().ToTable("Korpa");
            modelBuilder.Entity<KorpaInfo>().ToTable("KorpaInfo");
            modelBuilder.Entity<Narudzba>().ToTable("Narudzba");
            modelBuilder.Entity<Obavijest>().ToTable("Obavijest");
            modelBuilder.Entity<ChatObavijest>().ToTable("ChatObavijest");
            modelBuilder.Entity<NarudzbeObavijest>().ToTable("NarudzbeObavijest");
            modelBuilder.Entity<Recenzija>().ToTable("Recenzija");
            modelBuilder.Ignore<StanjeNarudzbe>();
            modelBuilder.Entity<Tip>().ToTable("Tip");
            modelBuilder.Ignore<Tipovi>();
            //Database.ExecuteSqlCommand("SET IDENTITY_INSERT Artikal ON");
            modelBuilder.Entity<Artikal>().ToTable("Artikal");
            ModelBuilderExtensions.PopuniBazu(modelBuilder);
        }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
        }


    }
}

Artikal.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Drawing.Imaging;
using System.ComponentModel.DataAnnotations;
using static System.Net.Mime.MediaTypeNames;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.IdentityModel.Protocols;
using System.Data.SqlClient;
using System.Text;
using System.Diagnostics;
using BestDeal.AdapteriPodataka;

namespace BestDeal.Models
{
    public class Artikal
    {
        private string nazivArtikla;
        private string kratkiOpis;
        private string detaljniOpis;
        private string URLSlike;
        private string URLMaleSlike;
        private Tip tipArtikla;
        double cijenaArtikla;
        //TODO: Mozda lista recenzija umjesto specificne ocjene artikla, ljepse izgleda
        double ocjenaArtikla;
        static int id = 100;
        int idArtikla = 110;
        [ScaffoldColumn(false)]
        private List<Recenzija> recenzije=new List<Recenzija>();

        public Artikal()
        {
            id++;
            Debug.WriteLine("dodijelio id {0}", Program.lastArtikalId);
            idArtikla = Program.lastArtikalId;
            Program.lastArtikalId++;
        }

        public Artikal(double cijenaArtikla, int idArtikla)
        {
            CijenaArtikla = cijenaArtikla;
            this.idArtikla = idArtikla;
           idArtikla = Program.lastArtikalId;
            Program.lastArtikalId++;
        }
        String tippp;
        [System.ComponentModel.DisplayName("Naziv tipa artikla")]
        public String tipNaziv {
            get
            {
                return tippp;
            }
            set
            {

                tippp = value;
              /*  Tip tip = new Tip();
                tip.Ime = value;
                Program.lastTipId++;
                tip.idTipa = Program.lastTipId;
                TipArtikla = tip;*/
            }
            }
        //TODO: Ovdje bi mozda bio koristan flyweight large-scale jer slike mogu biti velike u slucaju nekoliko hiljada artikala
        //public Image SlikaArtikla { get; }
        [Required]
        public Tip TipArtikla
        {
            get => tipArtikla;
            set
            {
                //ako postoji tip ne treba dodavati novi
                foreach (Tip t in Tipovi.getInstance().ListaTipova.ToList())
                    if (t.Equals(value)) tipArtikla = value;
                    else
                    {
                       /* Program.lastTipId++;
                        tipArtikla.idTipa = Program.lastTipId;*/
                        tipArtikla = value;
                        //ako je dodan tip koji ne postoji u listi tipova, automatski se azurira ta lista
                        Tipovi.getInstance().ListaTipova.Add(value);
                    }
            }
        }
        [Required(ErrorMessage ="This field is required.")]
        [System.ComponentModel.DisplayName("Naziv artikla")]
        public string NazivArtikla { get => nazivArtikla; set => nazivArtikla = value; }

        [Required(ErrorMessage = "This field is required.")]
        [System.ComponentModel.DisplayName("Cijena artikla")]
        public double CijenaArtikla { get => cijenaArtikla; set => cijenaArtikla = value; }
        [ScaffoldColumn(false)]
        [System.ComponentModel.DisplayName("Ocjena artikla")]
        public double OcjenaArtikla { get => ocjenaArtikla; }// set => ocjenaArtikla = value; }
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int IdArtikla { get => idArtikla; set => idArtikla = value; }
        [Required(ErrorMessage = "This field is required.")]
        [System.ComponentModel.DisplayName("Kratki opis")]
        public string KratkiOpis { get => kratkiOpis; set => kratkiOpis = value; }
        [Required(ErrorMessage = "This field is required.")]
        [System.ComponentModel.DisplayName("Detaljni opis")]
        public string DetaljniOpis { get => detaljniOpis; set => detaljniOpis = value; }
        [Required(ErrorMessage = "This field is required.")]
        [System.ComponentModel.DisplayName("URL slike")]
        public string URLSlike1 { get => URLSlike; set => URLSlike = value; }
        [Required(ErrorMessage = "This field is required.")]
        [System.ComponentModel.DisplayName("URL male slike")]
        public string URLMaleSlike1 { get => URLMaleSlike; set => URLMaleSlike = value; }

        public void DodajRecenziju(string tekstRecenzije, double ocjenaArtikla)
        {
            recenzije.Add(new Recenzija(tekstRecenzije, OcjenaArtikla));

            IzracunajOcjenu();
        }

        void IzracunajOcjenu()
        {
            double suma = 0.0;

            foreach (Recenzija recenzija in recenzije)
            {
                suma += recenzija.OverallRating;
            }

            ocjenaArtikla = suma / recenzije.Count;
        }



    }
}

Tip.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace BestDeal.Models
{
    //klasa koja omogucava dodavanje tipova
    public class Tip
    {
        public Tip()
        {
        }
        //TODO:Moguce opcije nekog IDa ili liste specificnih polja koju ima svaki tip (radi razlicitih detalja kod recenzija i sl.)
        public Tip(string ime)
        {
            Ime = ime;
        }

        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int idTipa { get; set; }
        public string Ime { get;  set; }
        public override bool Equals(object obj)
        {
            var other = obj as Tip;
            if (other == null)
            {
                return false;
            }
            return other == this;
        }

        public override int GetHashCode()
        {
            return HashCode.Combine(idTipa);
        }

        public static bool operator ==(Tip Tip1, Tip Tip2)
        {
            if (Object.ReferenceEquals(Tip1, null) && Object.ReferenceEquals(Tip2, null))
                return true;

            if (Object.ReferenceEquals(Tip1, null) || Object.ReferenceEquals(Tip2, null))
                return false;

            return Tip1.Ime == Tip2.Ime;
        }
        public static bool operator !=(Tip Tip1, Tip Tip2)
        {
            return !(Tip1 == Tip2);
        }
    }
}


I expect that the seeding operation works and I am able to successfully migrate this database entry back to Azure. I'm open for all possibilities and different ways of achieving it, if such ways exist.

1
1
6/15/2019 10:37:51 AM

Accepted Answer

You are trying to use EF Core Model seed data which has the following specific requirements:

To add entities that have a relationship the foreign key values need to be specified

and

If the entity type has any properties in shadow state an anonymous class can be used to provide the values

Shortly, you cannot use navigation properties with this type of data seeding.

Which is your scenario means that

TipArtikla = ParoviTip["Laptopi"],

has no effect.

and you need to:

  1. Seed both Tip and Artikal entities with HasData.
  2. For Arktical, either add explicit FK property to the model, or use anonymous type (which could be quite annoying and error prone due to the lack of compile time support). In both cases the above line should become something like

    {TipArtikla_FK_PropertyName} = ParoviTip["Laptopi"].idTipa,
    
2
6/16/2019 10:22:31 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow