2013-04-04 119 views
2

我遇到了一个奇怪的问题,我已经知道为什么正常发生此异常以及如何通过Disablaing WillCascadeOnDelete在其中一个属性中将其解决为False。EF5和周期或多个级联路径,FOREIGN KEY

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

Memeber:

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

并在成员配置中:

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

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

     }); 

正如你看到一个消息hase发件人与ForeignKey SenderID,一对多bidirrectional。 和成员有两个消息列表作为收件人和一个列表作为发件人。 我试图禁用级联删除其中一个关系(第一个) 但我仍然从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) 

回答

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

而且我需要将此MessagejoinMembers添加到我的DbContext? – 2013-04-04 16:30:04

+0

只要这个模型不需要(你给我在这里)。两者都可以工作 - 而且这种方法很好(上面的部分 - 例如'解决方案') - 我没有看到任何问题,这与我在几个地方使用的完全相同。如果你有一些错误 - 那么这是别的给你的错误。 – NSGaga 2013-04-04 16:46:38

+0

但是,我给了你第二个选择 - 以防万一 - 这很好 - 因为它越复杂,如果你真的拥有所有的表并拥有对字段的访问权,就会更容易处理。还有'性能方面',谈论总是'fk领域'的定义,因为这使事情变得更快 - 我猜这也w /索引/连接表。 – NSGaga 2013-04-04 16:47:59

相关问题