2017-09-25 190 views
2

我正在尝试创建一个小型演示解决方案来实验EF CF级联删除。实体框架代码第一个级联删除一对多

随着我写的代码,我试图添加一个人与2辆汽车时出现以下错误。

目标是添加一辆2辆车的人。然后删除该人,同时连接的汽车被删除。

System.InvalidCastException:无法转换类型的对象 'System.Collections.Generic.List`1 [EF_Cascading_Delete_Experiment.Car]' 为类型 'EF_Cascading_Delete_Experiment.Car'。

我想建立一个简单的例子,其中有一个与汽车列表的人

这里是我的人&车班:

public class Person 
{ 
    [Key] 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public List<Car> Cars { get; set; } 
} 
public class Car 
{ 
    [Key] 
    public int id { get; set; } 
    public string CarName { get; set; } 
} 

这里是我的简单的代码试图广告与2辆车的人:

public static void CarTest() 
    { 
     using (Model1 db = new Model1()) 
     { 
      Person personToAdd = new Person(); 
      personToAdd.Name = "trev"; 
      personToAdd.Cars = new List<Car>(); 

      Car car1 = new Car 
      { 
       CarName = "Vectra" 
      }; 

      Car car2 = new Car 
      { 
       CarName = "Focus" 
      }; 

      personToAdd.Cars.Add(car1); 
      personToAdd.Cars.Add(car2); 

      db.Person.Add(personToAdd); 

      db.SaveChanges(); 
     } 
    } 

错误发生在行

db.Person.Add(personToAdd); 

这是我的DbContext:

public class Model1 : DbContext 
{ 
    // Your context has been configured to use a 'Model1' connection string from your application's 
    // configuration file (App.config or Web.config). By default, this connection string targets the 
    // 'EF_Cascading_Delete_Experiment.Model1' database on your LocalDb instance. 
    // 
    // If you wish to target a different database and/or database provider, modify the 'Model1' 
    // connection string in the application configuration file. 
    public Model1() 
     : base("name=Model1") 
    { 
    } 

    // Add a DbSet for each entity type that you want to include in your model. For more information 
    // on configuring and using a Code First model, see http://go.microsoft.com/fwlink/?LinkId=390109. 

    public virtual DbSet<Person> Person { get; set; } 
    public virtual DbSet<Car> Car { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<Person>() 
      .HasOptional(a => a.Cars) 
      .WithOptionalDependent() 
      .WillCascadeOnDelete(true); 
    } 
} 

由EF生成的迁移代码看起来是这样的:

public partial class addedbackeverythingincludingcascadingdelete : DbMigration 
{ 
    public override void Up() 
    { 
     CreateTable(
      "dbo.Cars", 
      c => new 
       { 
        id = c.Int(nullable: false, identity: true), 
        CarName = c.String(), 
       }) 
      .PrimaryKey(t => t.id); 

     CreateTable(
      "dbo.People", 
      c => new 
       { 
        Id = c.Int(nullable: false, identity: true), 
        Name = c.String(), 
        Cars_id = c.Int(), 
       }) 
      .PrimaryKey(t => t.Id) 
      .ForeignKey("dbo.Cars", t => t.Cars_id, cascadeDelete: true) 
      .Index(t => t.Cars_id); 

    } 

    public override void Down() 
    { 
     DropForeignKey("dbo.People", "Cars_id", "dbo.Cars"); 
     DropIndex("dbo.People", new[] { "Cars_id" }); 
     DropTable("dbo.People"); 
     DropTable("dbo.Cars"); 
    } 
} 

对我来说,它看起来像迁移代码是不正确的?这将根据我的人&汽车类生成。但我不知道为什么?

当我查看数据库中的表格时,他们看起来不对。

enter image description here

当然在车表应该有一个PERSONID? Person表中没有CarId?

SOLUTION:

非常感谢伊万这是我的解决方案。我把它放在这里,所以我可以将他的问题标记为答案。

我的类现在这个样子:

public class Person 
{ 
    [Key] 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public virtual List<Car> Cars { get; set; } 
} 
public class Car 
{ 
    [Key] 
    public int id { get; set; } 
    public string CarName { get; set; } 
} 

测试时,即使伊万说,我不应该需要它,我发现了级联删除是行不通的,除非我保留了这个代码:

modelBuilder.Entity<Person>() 
      .HasMany(a => a.Cars) 
      .WithOptional() // or `WithRequired() in case Car requires Person 
      .WillCascadeOnDelete(true); 
+0

虚拟关键字尝试。例如'public virtual ICollection Cars {get;组; }'而不是'公开列表 Cars {get;组; } –

+0

@AmitKumar同样的错误。 –

+0

如果一个人可以有很多车,那么你的关系是错误的。汽车应该有一个Person_Id FK,而不是相反。看看你的链接图像,它显示了一个(许多人到一辆车)的关系,而不是(一个人到多辆车)的关系。 – Flater

回答

4

的流利关系配置

modelBuilder.Entity<Person>() 
    .HasOptional(a => a.Cars) 
    .WithOptionalDependent() 
    .WillCascadeOnDelete(true); 

是错误的。 HasOptional,HasRequired,WithOptionalDependent,WithOptionalPrincipal等是one-to-one关系,而你有one-to-many

正确的配置如下:

modelBuilder.Entity<Person>() 
    .HasMany(a => a.Cars) 
    .WithOptional() // or `WithRequired() in case Car requires Person 
    .WillCascadeOnDelete(true); 

现在迁移应该是这样的:

CreateTable(
    "dbo.People", 
    c => new 
     { 
      Id = c.Int(nullable: false, identity: true), 
      Name = c.String(), 
     }) 
    .PrimaryKey(t => t.Id); 

CreateTable(
    "dbo.Cars", 
    c => new 
     { 
      id = c.Int(nullable: false, identity: true), 
      CarName = c.String(), 
      Person_Id = c.Int(), 
     }) 
    .PrimaryKey(t => t.id) 
    .ForeignKey("dbo.People", t => t.Person_Id, cascadeDelete: true) 
    .Index(t => t.Person_Id); 
+0

你认为我的课是正确的吗? –

+0

也 - 当我看着人与汽车之间的关系时,它表示删除和更新规则是“无动作” –

+0

这是表示“一对多”的可能*有效* EF模型之一 - 具有集合导航属性在*一方*。您也可以在许多方面添加参考导航和/或FK属性,但这不是*必需*。 –

1

其实您还没有在您的汽车模型类中添加Person属性。 你的模型应该是这样的。

请看这里。Cascade delete in one to many relationship

public class Person 
{ 
    [Key] 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public virtual ICollection<Car> Cars { get; set; } 
} 
public class Car 
{ 
    [Key] 
    public int id { get; set; } 
    public string CarName { get; set; } 
    public virtual Person Person { get; set;} 
} 

现在运行迁移。并测试它。

1

首先,我认为这是更好地加入Person类虚拟关键字(延迟加载):

public virtual List<Car> Cars { get; set; } 

您可以将参照人上车类所需添加注释

[Required] 
public virtual Person Person { get; set; } 

因为需要一个人,删除一个人将级联删除他所有的汽车。