多重约束违反了SQL Server 2008 - CodeFirst

Fra*_*sco 8 entity-framework code-first sql-server-2008

我正在努力解决一个非常乏味的问题.我有一个名为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;}
}
Run Code Online (Sandbox Code Playgroud)

我正在使用EF 4和CodeFirst与一个名为NationsDB的DbContext来管理我在SQL Server 2008上的数据库.如果我创建一个Nation类型的新对象,我尝试调用countriesDB.SaveChanges,我得到以下异常:

"违反了多重约束.关系'CodeFirstNamespace.NationAlly_toNation'的角色'NationAlly_toNation_Target'具有多重性1或0..1."

我试图用NationAllies字段保存Nation字段为null并且不抛出此异常,数据库中的country表获取所有正确的值.

在我的数据库中,表Nation有2个字段:ID(主键),名称表NationAlly有3个字段:ID(主键),level,NationID这两个表链接的关系是NationAlly.NationID是外键和Nation .ID是主键.

不奇怪吗?在我眼中,NationAlly表应该有一个名为NationID1的字段,另一个叫做NationID2,以创建一个国家和其他国家名单之间的"关系".

我做错了什么?

Sla*_*uma 11

你也许它会自动创建的关系的EF代码优先映射约定的受害者NationAlliestoNation你不希望有.

如果我理解正确(但我不是百分之百确定,如果我这样做),你实际上想要有两个关系,并且你只暴露了每个实体中关系的一端.所以,NationAllies不要指向toNationNationAlly实体中的"看不见的"所有者国家.

如果是这种情况,则需要显式覆盖约定映射.在EF 4.1的Fluent API中,这可能如下所示:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这种映射将创建两个外键OwnerID,并NationIDNationAllies表中,都指向主键IDNations表.

编辑

这是我测试过的应用程序:

  • 在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;
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以在"throw"上设置断点,以在调试器中查看e中的可能异常.

NationsApp.NationsContext如果您使用的是SQL Server Express,并且没有定义任何其他连接字符串,则会创建一个名为的数据库.

它给出两个关系Nation_NationAllies(FK是"OwnerID")和NationAlly_toNation(FK是"NationID").所有列都是不可为空的.DB中的结果如下:

国家和民族


Che*_*les 6

如果这有助于某人得到此错误...我在进行查询而不是保存到数据库时收到此消息.我的数据设计:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

问题出在构造函数中.当你在那里初始化关联时,EF4.1不喜欢!我删除了那个构造函数,事情又开始了.