2

奇妙な問題が発生しました。通常、この例外が発生する理由と、プロパティの1つで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");

        });

ご覧のとおり、メッセージには、1 対多の双方向の、ForeignKey SenderID を持つ送信者が含まれています。メンバーには、受信者として 1 つと送信者として 1 つのリストの 2 つのメッセージ リストがあります。これらのリレーションの 1 つ (最初のもの) で削除時にカスケードを無効にしようとしましたが、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)
4

1 に答える 1

3

これはうまくいくはずです(あなたが持っているものと同じです)

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();
于 2013-04-04T14:48:01.300 に答える