实现聊天功能时,多重约束违反了错误

时间:2016-07-07 06:44:02

标签: c# asp.net asp.net-mvc entity-framework ef-code-first

我正在asp.net中像这一样兴奋地实现Chat functionality。这是模型解释Model is like this

我的课程是:用户,对话和留言:

public class User
{        
    public Guid Id { get; set; }
    public string Name { get; set; }
    public bool Active { get; set; }
    public string UserName { get; set; }       
    //keys       
    public ICollection<Conversation> Conversations { get; set; }
}
public class Conversation
{        
    public Guid ID { get; set; }
    public ICollection<Message> Messages { get; set; }
    public User RecipientUser { get; set; }
    public Guid SenderUserId { get; set; }
    public DateTime CreatedDate { get; set; }
    public DateTime ModifiedDate { get; set; }
}

最后,

public class Message
{

    public int ID { get; set; }
    public string Text { get; set; }
    public bool IsDelivered { get; set; }
    public bool IsSeen { get; set; }
    public Guid SenderUserId { get; set; }
    public Conversation Conversation { get; set; }
    public DateTime CreatedDate { get; set; }
    public DateTime ModifiedDate { get; set; }
}

我使用流畅的Api使用EntityTypeConfiguration:

public class UserConfig : EntityTypeConfiguration<User>
{
    public UserConfig()
    {
        HasMany(x => x.Conversations).WithRequired(x => x.RecipientUser).HasForeignKey(x => x.SenderUserId);
    }
}
 public class ConversationConfig : EntityTypeConfiguration<Conversation>
{
    public ConversationConfig()
    {
        HasKey(x => x.ID);
        HasRequired(x => x.RecipientUser).WithMany(x => x.Conversations);
        HasMany(x => x.Messages).WithRequired(x => x.Conversation).HasForeignKey(x => x.SenderUserId);           
    }
}

但我收到的错误如下: 违反了多重约束。 “DataAcessLayer.Conversation_RecipientUser”关系的“Conversation_RecipientUser_Target”角色具有多重性1或0..1。

如果有人可以帮助我。非常感谢!!!

2 个答案:

答案 0 :(得分:1)

当我使用你的模型时,我没有得到异常,但这并不重要,因为你无论如何都要做出一些改变。

首先,UserConfig ...

中的此配置
HasMany(x => x.Conversations).WithRequired(x => x.RecipientUser)
              .HasForeignKey(x => x.SenderUserId);

......对我没有意义。这意味着对话属于收件人,而不属于发件人,这本身就有些意外。但是外键的名称是SenderUserId。如果您将对象保存到此模型中,SenderUserId将获得收件人ID的值!

其次,假设前一个点是错误,那么通过定义......

会使它变得更加困难
public User RecipientUser { get; set; }
public Guid SenderUserId { get; set; }

这意味着您只能通过Conversation上的明确加入从User导航到发件人SenderUserId。相反,您只能通过设置RecipientUser来设置收件人,而不是简单地设置外键值。

第三,SenderUserId中不应该有Message。它应该是ConversationId。您可以通过其所属的Message找到Conversation的发件人。

总而言之,我将模型更改为此模型,将其简化为最低限度,并将int用于ID,因为它更容易阅读:

public class User
{
    public int ID { get; set; }
    public string Name { get; set; }
    public ICollection<Conversation> Conversations { get; set; }
}

public class Conversation
{
    public int ID { get; set; }
    public int SenderUserID { get; set; }
    public User SenderUser { get; set;}
    public int RecipientUserID { get; set; }
    public User RecipientUser { get; set; }
    public ICollection<Message> Messages { get; set; }
}

public class Message
{
    public int ID { get; set; }
    public string Text { get; set; }
    public int ConversationID { get; set; }
    public Conversation Conversation { get; set; }
}

唯一的配置:

public class ConversationConfig : EntityTypeConfiguration<Conversation>
{
    public ConversationConfig()
    {
        HasKey(c => c.ID);
        HasRequired(c => c.SenderUser).WithMany(u => u.Conversations)
                          .HasForeignKey(c => c.SenderUserID).WillCascadeOnDelete(true);
        HasRequired(c => c.RecipientUser).WithMany()
                          .HasForeignKey(c => c.RecipientUserID).WillCascadeOnDelete(false);
        HasMany(c => c.Messages).WithRequired(x => x.Conversation)
                      .HasForeignKey(x => x.ConversationID);
    }
}

(其中一个外键没有级联删除,因为这会导致SQL-Server错误:多个级联路径)。

一个简单的测试:

using (DbContext db = new DbContext(connectionString))
{
    var send = new User { Name = "Sender" };
    db.Set<User>().Add(send);

    var rec = new User { Name = "Recipient" };
    var messages = new[] { new Message { Text = "a" }, new Message { Text = "b" } };
    var conv = new Conversation { SenderUser = send, RecipientUser = rec, Messages = messages };

    db.Set<User>().Add(rec);
    db.Set<Conversation>().Add(conv);

    db.SaveChanges();
}

结果:

用户:

ID    Name
1     Recipient
2     Sender

Converstions:

ID    RecipientUserID    SenderUserID
11    1                  2

消息:

ID    Text    ConversationID
21    a       11
22    b       11

答案 1 :(得分:0)

给定Conversation有1个用户外键列,它调用SenderUserId

    // Here you set the user key for the old user! 
    conversation.RecipientUser = user;

    // Here you are trying to change Conversation.SenderUserId from other user (currentUser)
    currentUser.Conversations.Add(conversation);

如您所见,添加到收藏中的用户与您分配给对话1的内容不同.n无法以这种方式正常工作。

EF尝试用异常对你说,你试图添加/更改更多然后实体为releshinship一到零或一,错误消息有点雾我会说错误消息应该像&#34;一对多导航属性应该使用相同的实体&#34;

解决方案1)

    //  conversation.RecipientUser = user; remove this line why you need it?! 

解决方案2)

在CurrentUser的对话框1中创建一个新属性,为User

创建另一个属性
public class User
{
  public User()
  {
   Conversations = new List<Conversation>();
   CurrentUserConversations = new List<Conversation>();
   }

   public Guid Id { get; set; }
   public string Name { get; set; }
   public bool Active { get; set; }
   public string UserName { get; set; }
   public ICollection<Conversation> Conversations { get; set; }
   public ICollection<Conversation> CurrentUserConversations { get; set; }
}

public class Conversation
{
 public Conversation()
 {
  Messages = new List<Message>();
 }
 public Guid ID { get; set; }
 public User RecipientUser { get; set; }
 public Guid SenderUserId { get; set; }
 public User CurrentUser { get; set; }
 public Guid? CurrentUserId { get; set; }
 public ICollection<Message> Messages { get; set; }
}

public class UserConfig : EntityTypeConfiguration<User>
{
 public UserConfig()
 {
  HasMany(x => x.Conversations).WithRequired(x => x.RecipientUser).HasForeignKey(x => x.SenderUserId);
  HasMany(x => x.CurrentUserConversations).WithOptional(x => x.CurrentUser).HasForeignKey(x => x.CurrentUserId);
 }
}

如何使用它:

var user = myDbContext.Users.First();

var currentUser = new User { Active = true, Id = Guid.NewGuid() };
myDbContext.Users.Add(currentUser);

var message = new Message { IsDelivered = true };

var conversation = new Conversation() { ID = Guid.NewGuid() };
conversation.Messages.Add(message);

conversation.CurrentUser = user;
currentUser.Conversations.Add(conversation);

myDbContext.Conversations.Add(conversation);
myDbContext.SaveChanges();