实体框架:一个或多个外键属性不可为空

时间:2018-08-28 06:53:07

标签: c# sql-server entity-framework exception entity-framework-6

我有一个非常复杂的数据库模型。我的程序计算了一些data+db entriesmodifies+generates new entries以更新并插入数据库中。

当我使用数据库上下文插入条目时,一切正常。但是当我尝试保存更改时:

  

{“操作失败:由于一个或多个外键属性不可为空,因此无法更改关系。对关系进行更改时,相关的外键属性设置为null如果外键不支持空值,则必须定义新的关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。“}

关于这个主题,我在SO上看到了太多问题。但是我的问题是模型太复杂了,我无法跟踪问题。 Entity Framework 6没有提供有关问题来源,关系名称,...

的任何信息。

是否有一种方法可以从Entity Framework获得更多帮助以找到问题的根源?

3 个答案:

答案 0 :(得分:1)

您必须分析您的对象以解决此问题。

这里有一些简单的代码来说明您的Exception

static void Main()
{
    using (MyDbContext ctx = new MyDbContext())
    {
        // Build a new object
        MyClass o = new MyClass() { Id = 1, ChildObject = null };

        // Add it to your Context (It's not in the DB yet!)
        ctx.MyObjects.Add(o);

        // Write all changes (the new object) to the Db
        ctx.SaveChanges();
    }
}

// You got some DbContext with a DbSet pointing to your Table "MyTable"
public class MyDbContext : DbContext
{
    public DbSet<MyClass> MyObjects { get; set; }
}

// You've got a class to map your table to some nice object.
[Table("MyTable")]
public class MyClass
{
    // Some column..
    [Key]
    public int Id { get; set; }

    // And some ForeignKey! Which maps a column with the Id to an object.
    [ForeignKey("ChildObjectId")]
    public MyClass ChildObject { get; set; }
}

在此示例中,我创建了一个Context添加对象并保存更改(在表中创建一个Insert)。

第一:在SaveChanges发生异常,因为属性“ ChildObject”可以设置为null,因为我们对该属性没有任何限制。

2nd:异常是Db异常。您的程序(可能)运行正确。但是qour Db告诉您,不允许在MyTable中没有引用ChildObject的行。

您必须问自己是否配置数据库错误(使该列可为空),或者您的程序忘记设置子级。

希望您能看到:您必须深入研究代码。您的“完整模型”存在问题,必须解决。

考虑阅读上下文的SQL日志。示例:ctx.Log = Console.WriteLine;(这里没有工作室,但我想我应该是这样的人。)

这样,您可以获取最后一个SQL查询并在Db上运行它,以获得更好的错误输出。

答案 1 :(得分:0)

发生问题是因为引用的表值直接与主表的c#对象内的主表相关联

CREATE TABLE [dbo].[MainTable](
            [MainId] [int],
            [Name] [varchar](50) NOT NULL
);

CREATE TABLE [dbo].[ReferedTable](
            [ReferId] [int],
            [MainId] [int] NOT NULL,
            [Name] [varchar](50) NULL
);

外键有约束

using (EF context = new EF())
{
        var values = context.MainTable.Include("ReferedTable");
        var referedValues = values.ReferedTable.ToList();

        foreach (var value in referedValues)
        {
            context.ReferedTable.DeleteObject(value);
        }
        context.SaveChanges();
}

如果您尝试执行以下操作,则会出现错误。因为ReferedTable已连接到主表,并且如果您对其进行了更改并保存,则EF会引发错误

using (EF context = new EF())
{
        var values = context.MainTable.Include("ReferedTable");
        var referedValues = values.ReferedTable.ToList();

        foreach (var value in referedValues)
        {
            values.ReferedTable.Remove(value);
        }
        context.SaveChanges();
}

答案 2 :(得分:0)

我按照以下步骤手动递归地访问了对象的每个子对象:

if(parent.child!=null){
    parent.childId=parent.child.id;
    parent.child=null;
}

通过这种方式,您可以从父对象中删除每个子对象,而只保留ID,因此EntityFramework不会进行任何错误的插入,并且仍然确信存在这种关系。