entity-framework - EF5 和循环或多级联路径,FOREIGN KEY

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

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

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

成员(member):

 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)

最佳答案

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

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();

关于entity-framework - EF5 和循环或多级联路径,FOREIGN KEY,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15812227/

相关文章:

c# - Linq 中的左修剪

ASP.NET EFCodeFirst 未使用正确的连接字符串

c# - Entity Framework 一对多关系——外键名称命名为Id时如何重命名?

nhibernate - 如何处理 API 中的多对多关系

ios - 如何在 iOS 中建立多对多关系? (核心数据)

java - 每次在多对多关系中插入新数据时,以前的数据都会被删除

c# - 为什么在插入这些记录时会出现主键冲突? (EF4 代码优先)

c# - Entity Framework 指南

c# - 使用 Entity Framework 分离数据层和域层的正确方法

c# - Entity Framework 6 延迟加载不起作用