Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Multiplizitätseinschränkung verletzt SQL Server 2008 – CodeFirst

Möglicherweise sind Sie ein Opfer der EF Code-First-Mapping-Konventionen, die automatisch eine Beziehung zwischen NationAllies erstellen und toNation die du nicht haben willst.

Wenn ich Sie richtig verstehe (aber ich bin mir nicht 100-prozentig sicher, ob ich das tue), möchten Sie eigentlich zwei Beziehungen haben, und Sie haben nur ein Ende der Beziehung in jeder der Entitäten offengelegt. Also, NationAllies zeigt NICHT auf toNation sondern an eine "unsichtbare" Eigentümernation in Ihrem NationAlly Entität.

In diesem Fall müssen Sie die Konventionszuordnungen explizit überschreiben. In der Fluent-API von EF 4.1 könnte dies so aussehen:

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);
    }
}

Diese Zuordnung würde die beiden Fremdschlüssel OwnerID erzeugen und NationID in den NationAllies Tabelle, die beide auf den Primärschlüssel ID zeigen in den Nations Tabelle.

Bearbeiten

Hier ist die Anwendung, mit der ich getestet habe:

  • Erstellen Sie eine neue Konsolen-App in VS2010 / .NET 4.0, nennen Sie sie "NationsApp"
  • Fügen Sie einen Verweis auf "EntityFramework.dll" hinzu
  • Löschen Sie den Inhalt von "Program.cs" und fügen Sie stattdessen Folgendes ein in:

Inhalt von 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;
                }
            }
        }
    }
}

Sie können einen Haltepunkt auf "throw" setzen, um mögliche Ausnahmen in e im Debugger zu beobachten.

Dadurch wird eine Datenbank namens NationsApp.NationsContext erstellt wenn Sie SQL Server Express verwenden und keine weiteren Verbindungszeichenfolgen definiert haben.

Es gibt zwei Beziehungen Nation_NationAllies (FK ist "OwnerID") und NationAlly_toNation (FK ist "NationID"). Alle Spalten sind nicht-nullable. Das Ergebnis in der DB ist folgendes: