繁体   English   中英

实体框架,代码优先建模和循环引用

[英]Entity Framework, Code First modeling and a cyclical reference

我已经花了几天时间,试图解决这个问题。 在做一个简单的项目来说明我的问题时,我偶然发现了一个可能的解决方案。 因此,这是一个双重问题。

但首先,请提供一些背景信息:

我刚刚开始使用Entity Framework 4.1(EF)和Code First为我的ASP.NET MVC项目创建模型。 我需要一些类似的模型:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace TestApp.Models
{
    public class Family
    {
        public int ID { get; set; }
        public string Name { get; set; }

        public virtual ICollection<Father> Fathers { get; set; }
        public virtual ICollection<Mother> Mothers { get; set; }
    }

    public class Mother
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int FamilyID { get; set; }

        public virtual ICollection<Child> Children { get; set; }
        public virtual Family Family { get; set; }
    }

    public class Father
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int FamilyID { get; set; }

        public virtual ICollection<Child> Children { get; set; }
        public virtual Family Family { get; set; }
    }

    public class Child
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int MotherID { get; set; }
        public int FatherID { get; set; }

        public virtual Mother Mother { get; set; }
        public virtual Father Father { get; set; }
    }
}

和DbContext:

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

namespace TestApp.Models
{
    public class TestContext : DbContext
    {
        public DbSet<Family> Families { get; set; }
        public DbSet<Mother> Mothers { get; set; }
        public DbSet<Father> Fathers { get; set; }
        public DbSet<Child> Children { get; set; }
    }
}

(请原谅这个la脚的例子,这就是我星期五的炒脑所能想到的。)

一个家庭可以有几个母亲和几个父亲。 一个孩子有一个母亲和一个父亲。 我与工作中的一位.NET专家进行了核对,后者同意其中没有什么特别之处。 至少据我们所见。

但是,当我运行代码时,出现以下异常:

System.Data.SqlServerCe.SqlCeException:引用关系将导致不允许的循环引用。 [约束名称= Mother_Family]

我确实看到了周期: Family - Mother - Child - Father - Family 但是,如果我自己创建数据库表(我不喜欢这样做,那是我对Code First的喜欢),就我所知,这将是一个完全有效的数据结构。

所以,我的第一个问题是:为什么先使用代码时会出现问题? 有没有办法告诉EF如何正确处理周期?

然后,正如我最初编写的那样,在创建一个简单的项目来举例说明我的问题时,我偶然发现了一个可能的解决方案。 定义模型时,我只是忘记了一些属性。 为了清楚起见,在下面的示例中,我没有删除它们,而是注释掉了我忘记的模型部分:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace TestApp.Models
{
    public class Family
    {
        public int ID { get; set; }
        public string Name { get; set; }

        public virtual ICollection<Father> Fathers { get; set; }
        public virtual ICollection<Mother> Mothers { get; set; }
    }

    public class Mother
    {
        public int ID { get; set; }
        public string Name { get; set; }
        // public int FamilyID { get; set; }

        public virtual ICollection<Child> Children { get; set; }
        public virtual Family Family { get; set; }
    }

    public class Father
    {
        public int ID { get; set; }
        public string Name { get; set; }
        // public int FamilyID { get; set; }

        public virtual ICollection<Child> Children { get; set; }
        public virtual Family Family { get; set; }
    }

    public class Child
    {
        public int ID { get; set; }
        public string Name { get; set; }
        // public int MotherID { get; set; }
        // public int FatherID { get; set; }

        public virtual Mother Mother { get; set; }
        public virtual Father Father { get; set; }
    }
}

因此,删除这些SomethingID参考属性似乎可以解决我的问题。 正如您在本文末尾链接到的示例项目的控制器中所看到的那样,我仍然可以一直循环浏览并执行诸如mothers.First().Family.Fathers.First().Children.First().Mother.Family.Name没有任何问题。 但是我一直在研究的所有有关EF和Code First建模的教程和示例(例如Scott Guthrie的这篇文章 )都包含了这些属性,因此不使用它们会让人感到不对。

因此,我的第二个问题是:这样做还不会发现任何弊端和问题吗?

在此处下载示例项目: http ://blackfin.cannedtuna.org/cyclical-reference-test-app.zip,然后打开TestSolution.sln。 这些属性在示例项目中被注释掉。 取消注释TestModels.cs中的行以添加属性,从而导致循环引用异常。

注意:解决方案是创建和播种位于c:\\ TestApp.sdf的SQL CE数据库

更新,2011年12月:我从技术上从未解决过这个问题,但是我辞掉了工作,找到了另一项不必使用Microsoft技术的工作。 那种解决了我的问题:)

在解决问题时,原为技术支持的地方是:“已提供解决方法或解决方案”。

但是,如果我自己创建数据库表(我不喜欢这样做,那是我对Code First的喜欢),就我所知,这将是一个完全有效的数据结构。

您应该仔细检查这一点。 异常直接来自数据库,而不是实体框架。 具有手动创建的具有相同约束的表结构也可能无效。 请记住,您的外键属性Mother.FamilyIDFather.FamilyIDChild.MotherIDChild.FatherID 不可为空 ,因此它们表示必需的关系,并且数据库中的相应列也不可为空。

当您从模型类中删除所有这些属性时,由于导航属性可以为null因此关系突然变得可选 现在这是另一个模型,因为数据库中的FK列可以为空! 显然,这是允许的模型。

如果您希望模型中仍然具有表示可选关系而非必需关系的外键属性,则可以使用可为空的类型: public int? FamilyID { get; set; } public int? FamilyID { get; set; } public int? FamilyID { get; set; }public int? MotherID { get; set; } public int? MotherID { get; set; } public int? MotherID { get; set; }

我遇到了几乎相同的问题,但是我使用此答案中的建议解决了问题实体框架代码优先-来自同一表的两个外键比将键列的类型更改为可选更好。

这是一个已知的问题,您不是第一个遇到此问题的人。 据我所知,他们正在为即将到来的WCF版本中的更好的解决方案而努力,但是从我的经验来看,暂时最好创建DataContracts来表示要通过网络发送的数据,从而改变数据结构删除循环引用。

我知道这很痛苦,但是还有其他好处,因为您很可能希望对客户机无论如何都要使用的结构进行其他更改,而不是让它们玩数据库中存在的对象

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM