Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Contrainte de multiplicité violée SQL Server 2008 - CodeFirst

Vous êtes peut-être victime des conventions de mappage EF Code-First qui créent automatiquement une relation entre NationAllies et toNation vous ne voulez pas avoir.

Si je vous comprends bien (mais je ne suis pas sûr à 100 %, si c'est le cas), vous voulez en fait avoir deux relations et vous n'avez exposé qu'une seule extrémité de la relation dans chacune des entités. Alors, NationAllies ne pointe PAS vers toNation mais à une nation Propriétaire "invisible" dans votre NationAlly entité.

Si tel est le cas, vous devez écraser explicitement les mappages de convention. Dans l'API Fluent d'EF 4.1, cela pourrait ressembler à :

public class MyContext : DbContext
{
    public DbSet<Nation> Nations { get; set; }
    public DbSet<NationAlly> NationAllies { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Nation>()
            .HasMany(n => n.NationAllies)
            .WithRequired()
            .Map(conf => conf.MapKey("OwnerID"))
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<NationAlly>()
            .HasRequired(a => a.toNation)
            .WithMany()
            .Map(conf => conf.MapKey("NationID"))
            .WillCascadeOnDelete(false);
    }
}

Ce mappage créerait les deux clés étrangères OwnerID et NationID dans les NationAllies table, les deux pointant vers la clé primaire ID dans les Nations tableau.

Modifier

Voici l'application avec laquelle j'ai testé :

  • Créez une nouvelle application console dans VS2010/.NET 4.0, nommez-la "NationsApp"
  • Ajouter une référence à "EntityFramework.dll"
  • Effacez le contenu de "Program.cs" et collez à la place ce qui suit dans :

Contenu de Program.cs :

using System;
using System.Collections.Generic;
using System.Data.Entity;

namespace NationsApp
{
    public class Nation
    {
        public int ID { get; set; }
        public int name { get; set; }
        public List<NationAlly> NationAllies { get; set; }
    }

    public class NationAlly
    {
        public int ID { get; set; }
        public int level { get; set; }
        public Nation toNation { get; set; }
    }

    public class NationsContext : DbContext
    {
        public DbSet<Nation> Nations { get; set; }
        public DbSet<NationAlly> NationAllies { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Nation>()
                .HasMany(n => n.NationAllies)
                .WithRequired()
                .Map(conf => conf.MapKey("OwnerID"))
                .WillCascadeOnDelete(false);

            modelBuilder.Entity<NationAlly>()
                .HasRequired(a => a.toNation)
                .WithMany()
                .Map(conf => conf.MapKey("NationID"))
                .WillCascadeOnDelete(false);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            using (var context = new NationsContext())
            {
                try
                {
                    // We have three Nations and two Allies
                    Nation nation1 = new Nation() {
                        NationAllies = new List<NationAlly>() };
                    Nation nation2 = new Nation() {
                        NationAllies = new List<NationAlly>() };
                    Nation nation3 = new Nation() {
                        NationAllies = new List<NationAlly>() };
                    NationAlly ally1 = new NationAlly();
                    NationAlly ally2 = new NationAlly();

                    // Nation1 has two Allies
                    // (Nation1 is the "owner" of both Allies)
                    nation1.NationAllies.Add(ally1);
                    nation1.NationAllies.Add(ally2);

                    // toNation of ally1 refers to Nation2
                    ally1.toNation = nation2;
                    // toNation of ally2 refers to Nation3
                    ally2.toNation = nation3;

                    context.Nations.Add(nation1);
                    context.Nations.Add(nation2);
                    context.Nations.Add(nation3);

                    context.SaveChanges();
                }
                catch (Exception e)
                {
                    throw;
                }
            }
        }
    }
}

Vous pouvez définir un point d'arrêt sur "throw" pour surveiller les exceptions possibles dans e dans le débogueur.

Cela crée une base de données appelée NationsApp.NationsContext si vous utilisez SQL Server Express et que vous n'avez défini aucune autre chaîne de connexion.

Cela donne deux relations Nation_NationAllies (FK est "OwnerID") et NationAlly_toNation (FK est "NationID"). Toutes les colonnes ne sont pas nullables. Le résultat dans la BD est le suivant :