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.
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:
Tip
and Artikal
entities with HasData
.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,