Entity framework 为什么实体框架只级联集合中的单个项?

Entity framework 为什么实体框架只级联集合中的单个项?,entity-framework,entity-framework-5,cascade,Entity Framework,Entity Framework 5,Cascade,我有一个代码优先的EF 5.0模型,其结构如下: public class Widget { public virtual Int32 Id { get; set; } public virtual String Name { get; set; } } public class Product { public virtual Int32 Id { get; set; } public virtual ICollection<Widget> Wi

我有一个代码优先的EF 5.0模型,其结构如下:

public class Widget 
{
    public virtual Int32 Id { get; set; }
    public virtual String Name { get; set; }
}

public class Product
{
    public virtual Int32 Id { get; set; }
    public virtual ICollection<Widget> Widgets { get; set; }
    public virtual AddWidget(Widget widget)
    {
        Guard.NotNull(widget);

        if (Widgets == null)
        {
            Widgets = new List<Widget>();
        }

        Widgets.Add(widget);
    }
}
此时,
Widget
表中只存在“Foo”。我使用SQL Server Profiler来检查进入数据库的数据,对于集合中添加了两个控件的第一个
小部件
,只发出一个
INSERT
语句


为什么EF不能在两个新实体上级联?

我不太确定,但我认为这是因为id中的virtual关键字

您说过首先是代码,数据库中的键表示不可变属性。允许覆盖该参数是令人困惑的,而且可能是不正确的

子元素的列表也定义为如下
this.Widgets=newhashset()这是一个更通用的列表。。。我要试一试


另外,我先使用了模型

您的问题在给出代码的情况下是不可复制的。我已经复制并粘贴了很多,修复了编译问题(AddWidget需要返回类型),删除了对
Guard
的调用,运行它,并看到两个小部件都出现在数据库中

这是完整的代码。希望您能够发现代码的不同之处

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

namespace EF_SO_Q
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var context = new ProductManagementContext())
            {
                var product = new Product();
                product.AddWidget(new Widget() { Name = "Foo" });
                product.AddWidget(new Widget() { Name = "Bar" });
                context.Products.Add(product);
                context.SaveChanges();
            }
        }
    }

    public class Widget
    {
        public virtual Int32 Id { get; set; }
        public virtual String Name { get; set; }
    }

    public class Product
    {
        public virtual Int32 Id { get; set; }
        public virtual ICollection<Widget> Widgets { get; set; }
        public virtual void AddWidget(Widget widget)
        {

            if (Widgets == null)
            {
                Widgets = new List<Widget>();
            }

            Widgets.Add(widget);
        }
    }

    public class ProductManagementContext : DbContext
    {
        public DbSet<Widget> Widgets { get; set; }
        public DbSet<Product> Products { get; set; }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Data.Entity;
命名空间EF_SO_Q
{
班级计划
{
静态void Main(字符串[]参数)
{
使用(var context=new ProductManagementContext())
{
var product=新产品();
product.AddWidget(新Widget(){Name=“Foo”});
product.AddWidget(新Widget(){Name=“Bar”});
context.Products.Add(产品);
SaveChanges();
}
}
}
公共类小部件
{
公共虚拟Int32 Id{get;set;}
公共虚拟字符串名称{get;set;}
}
公共类产品
{
公共虚拟Int32 Id{get;set;}
公共虚拟ICollection小部件{get;set;}
公共虚拟void AddWidget(Widget Widget)
{
if(Widgets==null)
{
Widgets=newlist();
}
Widgets.Add(widget);
}
}
公共类ProductManagementContext:DbContext
{
公共DbSet小部件{get;set;}
公共数据库集产品{get;set;}
}
}

不确定这是否相关,但为什么集合是在AddWidget()方法中初始化的,而不是在产品构造函数中初始化的?我很好奇这有什么区别?从设计的角度来看,它的初始化过于陈旧,但可能有一些实际原因导致EF强制覆盖设计决策,例如在构造后捕获属性状态。即便如此,由于我通过属性访问器对值进行了变异,行为上应该没有区别。这是一个愚蠢的问题,但我还是要问:所有ID上都有
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
属性,对吧?我假设这是一个更大项目的一部分。为了在更简单的上下文中重现,您是否尝试将这些片段提取到测试项目(例如控制台应用程序)中?如果这个问题(这不是正常行为)也发生在测试项目中,我会感到惊讶。您是否使用了我们不知道的特定库?
Guard
来自哪里?我也很好奇为什么所有字段都是
Virtual
。从您的示例中可以看到,唯一需要虚拟的字段是
publicvirtualicollection小部件{get;set;}
。当您定义
AddWidget
时,您的代码真的编译了吗?我还需要定义一个返回参数。但是,我在VS2013中使用EF5尝试了您的代码,并且Foo和Bar都保存在数据库中,因此我无法重现您的问题。
using System;
using System.Collections.Generic;
using System.Data.Entity;

namespace EF_SO_Q
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var context = new ProductManagementContext())
            {
                var product = new Product();
                product.AddWidget(new Widget() { Name = "Foo" });
                product.AddWidget(new Widget() { Name = "Bar" });
                context.Products.Add(product);
                context.SaveChanges();
            }
        }
    }

    public class Widget
    {
        public virtual Int32 Id { get; set; }
        public virtual String Name { get; set; }
    }

    public class Product
    {
        public virtual Int32 Id { get; set; }
        public virtual ICollection<Widget> Widgets { get; set; }
        public virtual void AddWidget(Widget widget)
        {

            if (Widgets == null)
            {
                Widgets = new List<Widget>();
            }

            Widgets.Add(widget);
        }
    }

    public class ProductManagementContext : DbContext
    {
        public DbSet<Widget> Widgets { get; set; }
        public DbSet<Product> Products { get; set; }
    }
}