Нарушено ограничение множественности SQL Server 2008 - CodeFirst - PullRequest
8 голосов
/ 24 марта 2011

Я работаю, чтобы решить очень утомительную проблему.У меня есть класс с именем Nation и класс с именем NationAlly

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

Я использую EF 4 и CodeFirst с DbContext с именем NationsDB для управления моей базой данных на SQL Server 2008. Если я создаю новый объект типаНация и я пытаемся вызвать NationsDB.SaveChanges, я получил следующее исключение:

"Нарушено ограничение множественности. Роль 'NationAlly_toNation_Target' в связи 'CodeFirstNamespace.NationAlly_toNation' имеет кратность 1 или 0..1."

Я пытался сохранить поле Nation with NationAllies, равное NULL, и это исключение не выдается, таблица нации в базе данных получает все правильные значения.

В моей базе данных таблица Nation имеет 2 поля: ID (первичный ключ), имя Таблица NationAlly имеет 3 поля: ID (первичный ключ), уровень, NationID. Эти две таблицы связаны отношением, в котором NationAlly.NationID - это внешний ключ, а Nation.ID - это первичный ключ.

Разве не странно?На мой взгляд, таблица NationAlly должна иметь поле с именем NationID1, а другое - с именем NationID2, чтобы создать «связь» между нацией и списком других наций.

Что я сделал не так?

Ответы [ 2 ]

11 голосов
/ 24 марта 2011

Вы, возможно, являетесь жертвой соглашений EF Code-First, которые автоматически создают отношения между NationAllies и toNation, которые вы не хотите иметь.

Если я вас правильно понимаю (ноЯ не уверен на 100 процентов, если я это сделаю), вы на самом деле хотите иметь два отношения, и вы раскрыли только один конец отношений в каждой из сущностей.Таким образом, NationAllies НЕ указывает на toNation, но указывает на "невидимую" нацию владельца в вашей NationAlly сущности.

В этом случае вам необходимо явно перезаписать отображения соглашений.В Fluent API в EF 4.1 это может выглядеть следующим образом:

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

Это сопоставление создаст два внешних ключа OwnerID и NationID в таблице NationAllies, оба указывают на первичный ключ ID в таблице Nations.

Редактировать

Вот приложение, которое я тестировал:

  • Создание новой консолиПриложение в VS2010 / .NET 4.0, назовите его «NationsApp»
  • Добавьте ссылку на «EntityFramework.dll»
  • Очистите содержимое «Program.cs» и вставьте вместо него следующее:

Содержимое 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;
                }
            }
        }
    }
}

Вы можете установить точку останова на "throw", чтобы просмотреть возможные исключения в e в отладчике.

Thisсоздает базу данных с именем NationsApp.NationsContext, если вы используете SQL Server Express и у вас не определены какие-либо дополнительные строки подключения.

Это дает две взаимосвязи Nation_NationAllies (FK - "OwnerID") и NationAlly_toNation (ФК это "NationID").Все столбцы не обнуляются.Результат в БД следующий:

Nations and NationAllies

6 голосов
/ 15 декабря 2011

В случае, если это помогает кому-то получить эту ошибку ... Я получал это сообщение, выполняя запросы, а не сохраняя в базу данных. Мой дизайн данных:

public class Base {
    public int Id {get; set;}
}

public class Child {
    [Key][ForeignKey("Base")] public int Id {get; set;}

    public virtual Base Base {get; set;}

    public Child() {
        Base = new Base();
    }
}

Проблема была в конструкторе. Оказывается, EF4.1 не нравится, когда вы инициализируете ассоциации там! Я удалил этот конструктор, и все снова заработало.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...