Lordful
Lordful

Reputation: 21

Entity with same primary key in an inheritance TPC

I create a website in ASP.NET MVC 4 and i have this error that i can't understand :

All objects EntitySet 'DataContext.Strategies' must have unique primary keys. However, an instance of type 'AuctionSelling' and an instance of type 'DirectSelling' have the same primary key value, 'EntitySet = Strategies; Id = 0'.

So this is a problem of primary key but i don't understand why it happens.

I use the strategy TPC for my inheritance and this is my class :

public abstract class SellingStrategy
{
    public long Id { get; set; }
    public DateTime SoldDate { get; set; }
    public abstract float getSoldPrice();
}


public class DirectSelling : SellingStrategy
{
    public float SoldPrice { get; set; }

    public override float getSoldPrice()
    {
        return SoldPrice;
    }
}


public class AuctionSelling : SellingStrategy
{
    public float BasePrice { get; set; }
    public DateTime EndOfAuction { get; set; }

    public override float getSoldPrice()
    {
        return BasePrice;
    }
}

And this is my context :

public class DataContext : DbContext
{
    public DbSet<Article> Articles { get; set; }
    public DbSet<Utilisateur> Utilisateurs { get; set; }
    public DbSet<Adresse> Adresses { get; set; }

    public DbSet<SellingStrategy> Strategies { get; set; }

    public DataContext() : this ("DBAchatVente")
    {
    }

    public DataContext(string connectionString)
        : base(connectionString)
    {

    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Article>().HasKey<long>(a => a.Id);
        modelBuilder.Entity<Article>().Property(a => a.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        modelBuilder.Entity<Article>().Property(a => a.Nom).IsRequired();
        modelBuilder.Entity<Article>().Property(a => a.Description).IsRequired();
        modelBuilder.Entity<Article>().Property(a => a.UrlImage).IsRequired();

        modelBuilder.Entity<Article>().Ignore(a => a.IdVendeur);
        modelBuilder.Entity<Article>().Ignore(a => a.MailVendeur);
        modelBuilder.Entity<Article>().Ignore(a => a.MotDePasseVendeur);
        modelBuilder.Entity<Article>().Ignore(a => a.AdresseLivraisonVendeur);
        modelBuilder.Entity<Article>().Ignore(a => a.AdressePaiementVendeur);
        modelBuilder.Entity<Article>().Ignore(a => a.NomVendeur);
        modelBuilder.Entity<Article>().Ignore(a => a.PrenomVendeur);

        modelBuilder.Entity<Article>().Ignore(a => a.IdAcheteur);
        modelBuilder.Entity<Article>().Ignore(a => a.MailAcheteur);
        modelBuilder.Entity<Article>().Ignore(a => a.MotDePasseAcheteur);
        modelBuilder.Entity<Article>().Ignore(a => a.AdresseLivraisonAcheteur);
        modelBuilder.Entity<Article>().Ignore(a => a.AdressePaiementAcheteur);
        modelBuilder.Entity<Article>().Ignore(a => a.NomAcheteur);
        modelBuilder.Entity<Article>().Ignore(a => a.PrenomAcheteur);

        modelBuilder.Entity<Article>().HasOptional<Utilisateur>(u => u.UserAcheteur).WithMany().WillCascadeOnDelete(false);
        modelBuilder.Entity<Article>().HasRequired<Utilisateur>(u => u.UserVendeur).WithMany().WillCascadeOnDelete(false);

        modelBuilder.Entity<Article>().HasRequired<SellingStrategy>(a => a.Strategy).WithMany().WillCascadeOnDelete(false);
        modelBuilder.Entity<SellingStrategy>().Property(s => s.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
        modelBuilder.Entity<AuctionSelling>().HasKey<long>(s => s.Id);            
        modelBuilder.Entity<AuctionSelling>().Map(m => {
            m.MapInheritedProperties();
            m.ToTable("AuctionSelling");
        });
        modelBuilder.Entity<DirectSelling>().HasKey<long>(s => s.Id);   
        modelBuilder.Entity<DirectSelling>().Map(m =>
        {
            m.MapInheritedProperties();
            m.ToTable("DirectSelling");
        });
        modelBuilder.Entity<SellingStrategy>().Property<DateTime>(s => s.SoldDate).HasColumnName("DateVente").HasColumnType("datetime2").IsOptional();


        modelBuilder.Entity<Adresse>().HasKey<long>(a => a.Id);
        modelBuilder.Entity<Adresse>().Property(a => a.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        modelBuilder.Entity<Adresse>().Property(a => a.Rue).IsRequired();
        modelBuilder.Entity<Adresse>().Property<long>(a => a.Numero).IsRequired();
        modelBuilder.Entity<Adresse>().Property(a => a.Localite).IsRequired();
        modelBuilder.Entity<Adresse>().Property(a => a.Pays).IsRequired();

        modelBuilder.Entity<Utilisateur>().HasKey<long>(u => u.Id);
        modelBuilder.Entity<Utilisateur>().Property(u => u.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        modelBuilder.Entity<Utilisateur>().Property(u => u.Nom).IsRequired();
        modelBuilder.Entity<Utilisateur>().Property(u => u.Prenom).IsRequired();
        modelBuilder.Entity<Utilisateur>().Property(u => u.Mail).IsRequired();
        modelBuilder.Entity<Utilisateur>().Property(u => u.MotDePasse).IsRequired();

        modelBuilder.Entity<Utilisateur>().Ignore(u => u.RuePaiement);
        modelBuilder.Entity<Utilisateur>().Ignore(u => u.NumeroPaiement);
        modelBuilder.Entity<Utilisateur>().Ignore(u => u.LocalitePaiement);
        modelBuilder.Entity<Utilisateur>().Ignore(u => u.PaysPaiement);

        modelBuilder.Entity<Utilisateur>().Ignore(u => u.RueLivraison);
        modelBuilder.Entity<Utilisateur>().Ignore(u => u.NumeroLivraison);
        modelBuilder.Entity<Utilisateur>().Ignore(u => u.LocaliteLivraison);
        modelBuilder.Entity<Utilisateur>().Ignore(u => u.PaysLivraison);

        modelBuilder.Entity<Utilisateur>().HasRequired<Adresse>(a => a.AdresseLivraison).WithMany().WillCascadeOnDelete(false);
        modelBuilder.Entity<Utilisateur>().HasRequired<Adresse>(a => a.AdressePaiement).WithMany().WillCascadeOnDelete(false);
    }
}

The exception occurs when i try to get my articles, there is 2 articles which have the same ID for the strategy, even if each strategy is in a different table.

using (DataContext context = new DataContext(connexion))
        {
            var con = from article in context.Articles.Include("UserVendeur").Include("UserAcheteur").Include("Strategy")
                      select article;
            listeArticle = con.ToList<Article>();
        }

This is the line

listeArticle = con.ToList<Article>();

that provoke the error.

Upvotes: 1

Views: 1366

Answers (1)

tschmit007
tschmit007

Reputation: 7800

I think that the answer is here : https://msdn.microsoft.com/en-us/data/jj591617.aspx#2.6

Basically you can't have two objects of the same type (here your base class) with the same PK.

To achieve this you have to setup the identities of the table AuctionSelling and DirectSelling in the database with different seeds (0 and Int32.MinValue for example).

In sql server the needed command is : DBCC CHECKIDENT (DirectSelling, RESEED, 1000000000)

Upvotes: 1

Related Questions