【问题标题】:EF5 And cycles or multiple cascade paths, FOREIGN KEYEF5 和循环或多个级联路径,外键
【发布时间】:2013-03-26 14:06:06
【问题描述】:

我遇到了一个奇怪的问题,我已经知道为什么通常会发生此异常以及如何通过在其中一个属性中将 WillCascadeOnDelete 禁用为 False 来解决它。

但我的问题似乎是其他类型的, 这是我的代码:

会员:

 public class Memeber
       {
      public int MemberID { get; set; }
      public virtual ICollection<Message> SentMessages { get; set; }
      public virtual ICollection<Message> RecievedMessages { get; set; }
       }

    public class Message
    {
      public long MessageID { get; set; }
      public int SenderMemberId{ get; set; }
      public virtual ICollection<Member> RecipientsMembers { get; set; }
      [ForeignKey("SenderMemberId")]
      public virtual Member SenderMember { get; set; }
    }

这是映射: 在消息配置中:

    this.HasRequired(c => c.SenderMember)
            .WithMany(c => c.SentMessages)
            .HasForeignKey(c => c.SenderMemberId)
            .WillCascadeOnDelete(false);

在 MemberConfiguration 中:

 this.HasMany(c => c.RecievedMessages)
        .WithMany(c => c.RecipientsMembers)

        .Map(cm =>
        {
            cm.ToTable("MessageJoinMemeber");
            cm.MapLeftKey("MessageId");
            cm.MapRightKey("MemberId");

        });

如您所见,一条消息包含一个具有 ForeignKey SenderID 的发件人,一对多双向。 成员有 2 个消息列表,一个作为接收者,一个作为发送者。 我试图在其中一个关系中禁用级联删除(第一个) 但我仍然从 SQL 引擎得到同样的问题。 我也尝试从消息部分而不是从成员部分定义关系 与:

        this.HasMany(c => c.RecipientsMembers)
               .WithMany(c=> c.RecievedMessages)
               .Map ( cm =>
                {
                cm.ToTable("MessageJoinMemeber");
                cm.MapLeftKey("MessageId");
                cm.MapRightKey("MemberId");

                });

但我总是得到这个错误:

 System.Data.SqlClient.SqlException was unhandled by user code
  HResult=-2146232060
  Message=Introducing FOREIGN KEY constraint 'FK_dbo.MessageJoinMemeber_dbo.Messages_MemberId' on table 'MessageJoinMemeber' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.
  Source=.Net SqlClient Data Provider
  ErrorCode=-2146232060
  Class=16
  LineNumber=1
  Number=1785
  Procedure=""
  Server=KINGPC
  State=0
  StackTrace:
       at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
       at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
       at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)

【问题讨论】:

    标签: entity-framework many-to-many code-first


    【解决方案1】:

    这应该可以正常工作(它与您所拥有的相同

    public class Member
    {
        public int MemberID { get; set; }
        public string Name { get; set; }
        public virtual ICollection<Message> SentMessages { get; set; }
        public virtual ICollection<Message> RecievedMessages { get; set; }
    }
    public class Message
    {
        public long MessageID { get; set; }
        public int SenderMemberId { get; set; }
        public virtual ICollection<Member> RecipientsMembers { get; set; }
        [ForeignKey("SenderMemberId")]
        public virtual Member SenderMember { get; set; }
    }
    ...
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
    modelBuilder.Entity<Message>()
        .HasRequired(c => c.SenderMember)
        .WithMany(c => c.SentMessages)
        .HasForeignKey(c => c.SenderMemberId)
        .WillCascadeOnDelete(false);
    
    modelBuilder.Entity<Member>()
        .HasMany(c => c.RecievedMessages)
        .WithMany(c => c.RecipientsMembers)
        .Map(cm =>
        {
            cm.ToTable("MessageJoinMemeber");
            cm.MapLeftKey("MessageId");
            cm.MapRightKey("MemberId");
    
        });
    ...
    var member = new Member { Name = "sender1"  };
    db.Messages.Add(new Message
    {
        SenderMember = new Member { Name = "sender1" },
        RecipientsMembers = new List<Member> 
        {
            new Member { Name = "receiver1"  },
            new Member { Name = "receiver2"  },
            new Member { Name = "receiver3"  },
        }
    });
    db.SaveChanges();
    

    ...但是如果您仍然有问题,您可以手动创建连接表...

    // public virtual ICollection<Message> RecievedMessages { get; set; }
    public virtual ICollection<MessageJoinMember> Recieved { get; set; }
    ...
    // public virtual ICollection<Member> RecipientsMembers { get; set; }
    public virtual ICollection<MessageJoinMember> Recipients { get; set; }
    ...
    public class MessageJoinMember
    {
        public long MessageID { get; set; }
        public Message Message { get; set; }
        public int MemberID { get; set; }
        public Member Member { get; set; }
    }
    ...
    modelBuilder.Entity<Message>()
        .HasRequired(c => c.SenderMember)
        .WithMany(c => c.SentMessages)
        .HasForeignKey(c => c.SenderMemberId)
        .WillCascadeOnDelete(false);
    modelBuilder.Entity<MessageJoinMember>()
        .HasKey(x => new { x.MessageID, x.MemberID });
    modelBuilder.Entity<MessageJoinMember>()
        .HasRequired(x => x.Message)
        .WithMany(x => x.Recipients)
        .HasForeignKey(x => x.MessageID)
        .WillCascadeOnDelete(false);
    modelBuilder.Entity<MessageJoinMember>()
        .HasRequired(x => x.Member)
        .WithMany(x => x.Recieved)
        .HasForeignKey(x => x.MemberID)
        .WillCascadeOnDelete(false);
    // remove the implicit many-to-many here
    ...
    var message = new Message { SenderMember = new Member { Name = "sender1" }, };
    db.MessageJoinMembers.Add(new MessageJoinMember { Message = message, Member = new Member { Name = "receiver1" } });
    db.MessageJoinMembers.Add(new MessageJoinMember { Message = message, Member = new Member { Name = "receiver2" } });
    db.MessageJoinMembers.Add(new MessageJoinMember { Message = message, Member = new Member { Name = "receiver3" } });
    db.Messages.Add(message);
    db.SaveChanges();
    

    【讨论】:

    • 我是否需要将此 MessagejoinMembers 添加到我的 DbContext 中?
    • 就这个模型而言不需要(你在这里给我的)。两者都有效 - 而且效果很好(上面的部分 - 例如solution ) - 我没有看到任何问题,这与我在几个地方使用的完全相同。如果你有一些错误 - 那么它就是给你错误的其他东西。
    • 但是,我给了你第二个选项 - 以防万一 - 最好有 - 因为它越复杂,如果你真的“拥有”所有表格,它就会更容易处理 - 并且可以访问到字段等。还有一个“性能方面”,它谈到总是定义“fk 字段”,因为这会使事情变得更快——我猜这也适用于索引/连接表。
    • 我尝试了第二个选项,结果从 Sql 引擎得到了完全相同的错误。:(
    • 什么是 EF 版本?如果您还没有,请尝试 EF 5。你需要发布完整的模型和配置——一些可重复的东西——你显然有其他东西挡住了你的路——这应该可以正常工作(它有点复杂,但一切都很好)。甚至更好 - 试试我在这里发布的“原样”,没有额外的字段。
    猜你喜欢
    • 1970-01-01
    • 2016-03-26
    • 1970-01-01
    • 2010-10-25
    • 2010-12-10
    相关资源
    最近更新 更多