简体   繁体   English

实体框架核心中的模型循环

[英]Cycle in models in Entity framework core

Imagine these models are a part of a social network application.想象一下这些模型是社交网络应用程序的一部分。 User can make a Group and can add other users in it(as members) and a user can be a member of the group. User可以创建一个Group并可以在其中添加其他用户(作为成员),并且用户可以成为该组的成员。 I'm using .net core and also entity framework core.我正在使用 .net 核心和实体框架核心。

Models:楷模:

public class User : BaseEntity
{
    public string UserName { get; set; }

    public IList<Group> OwnGroups { get; set; }
    public IList<GroupMember> MemberInGroups { get; set; }
}

public class Group : BaseEntity
{
    public string Name { get; set; }
    public int OwnerUserId { get; set; }

    [ForeignKey("OwnerUserId")]
    public User OwnerUser { get; set; }

    public IList<GroupMember> Members { get; set; }
}

public class GroupMember : BaseEntity
{
    public int GroupId { get; set; }
    public int UserId { get; set; }

    [ForeignKey("UserId")]
    public User User { get; set; }

    [ForeignKey("UserId")]
    public Group Group { get; set; }
}

Fluent API:流畅的 API:

    modelBuilder.Entity<User>()
    .HasMany(x => x.OwnGroups)
    .WithOne(x => x.OwnerUser).HasForeignKey(x => x.OwnerUserId).IsRequired().OnDelete(DeleteBehavior.Cascade);

modelBuilder.Entity<User>()
    .HasMany(x => x.MemberInGroups)
    .WithOne(x => x.User).HasForeignKey(x => x.UserId).IsRequired().OnDelete(DeleteBehavior.Cascade);

modelBuilder.Entity<Group>()
    .HasMany(x => x.Members)
    .WithOne(x => x.Group).HasForeignKey(x => x.GroupId).IsRequired().OnDelete(DeleteBehavior.Cascade);

When I want to migrate to the database, this error happens:当我想迁移到数据库时,会发生这个错误:

Introducing FOREIGN KEY constraint 'FK_GroupMembers_Users_UserId' on table 'GroupMembers' may cause cycles or multiple cascade paths.在表“GroupMembers”上引入 FOREIGN KEY 约束“FK_GroupMembers_Users_UserId”可能会导致循环或多个级联路径。 Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。 Could not create constraint or index.无法创建约束或索引。 See previous errors.请参阅以前的错误。

However, I can make this model in SQL Server manually and there is no problem.但是,我可以在SQL Server手动制作这个模型,没有问题。 在此处输入图像描述

There are at least two ways to fix it.至少有两种方法可以修复它。 But I want to know why EF Core says, there is a cycle.但我想知道为什么EF Core说,有一个循环。 What's the problem is?问题是什么?

I think your bridge table has a problem. 我认为您的桥接表有问题。

Try this 尝试这个

public class GroupMember: BaseEntity
{
public User User { get; set; }
[Key, Column(Order = 0)]
public int UserId { get; set; }

public Group Group { get; set; }
[Key, Column(Order = 1)]
public int GroupId { get; set; }
}

First of all: Get rid of the Fluent API part首先:去掉 Fluent API 部分

//modelBuilder.Entity<User>()
//.HasMany(x => x.OwnGroups)
//.WithOne(x => x.OwnerUser).HasForeignKey(x => x.OwnerUserId).IsRequired().OnDelete(DeleteBehavior.Cascade);

//modelBuilder.Entity<User>()
//    .HasMany(x => x.MemberInGroups)
//    .WithOne(x => x.User).HasForeignKey(x => x.UserId).IsRequired().OnDelete(DeleteBehavior.Cascade);

//modelBuilder.Entity<Group>()
//    .HasMany(x => x.Members)
//    .WithOne(x => x.Group).HasForeignKey(x => x.GroupId).IsRequired().OnDelete(DeleteBehavior.Cascade);

And then, based on Microsoft Docs , choose one of these cases:然后,根据Microsoft Docs ,选择以下情况之一:

  1. Change one or more of the relationships to not cascade delete(make it nullable)将一个或多个关系更改为不级联删除(使其可为空)

     public int? OwnerUserId { get; set; }
  2. The second approach instead, we can keep the OwnerUserId relationship required(non-nullable) and configured for cascade delete, but make this configuration only apply to tracked entities, not the database.相反,第二种方法,我们可以保持OwnerUserId关系必需(不可为空)并配置为级联删除,但使此配置仅适用于跟踪实体,而不适用于数据库。

     modelBuilder .Entity<User>() .HasMany(e => e.OwnGroups) .WithOne(e => e.OwnerUser) .OnDelete(DeleteBehavior.ClientCascade);

In this way, if we want to delete a User and all its Groups , we should load both the User and its Groups in the application(RAM).这样,如果我们想删除一个User及其所有Groups ,我们应该在应用程序(RAM)中加载User及其Groups Look at this: After running this code, the User and all its Groups will be removed.看这个:运行此代码后, User及其所有Groups将被删除。

var context = new MyDbContext();

var user = context.Users.Single(x => x.UserName == "SampleName");
var groups = context.Groups.Where(x => x.OwnerUser == user).ToList();

context.Users.Remove(user);
context.SaveChanges();

But the code below will throw an exception.但是下面的代码会抛出异常。

var context = new MyDbContext();

var user = context.Users.Single(x => x.UserName == "SampleName");

context.Users.Remove(user);
context.SaveChanges();

Microsoft.Data.SqlClient.SqlException (0x80131904): Introducing FOREIGN KEY constraint 'FK_Groups_Users_OwnerUserId' on table 'Groups' may cause cycles or multiple cascade paths. Microsoft.Data.SqlClient.SqlException (0x80131904):在表 'Groups' 上引入 FOREIGN KEY 约束 'FK_Groups_Users_OwnerUserId' 可能会导致循环或多个级联路径。 Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。

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

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