简体   繁体   English

实体框架中的迭代错误

[英]Iteration error in Entity Framework

I'm creating a simple Messaging application with C# Winforms. 我正在使用C#Winforms创建一个简单的Messaging应用程序。 I'm connecting to a SQLEXPRESS server running on my computer and storing everything there. 我正在连接到计算机上运行的SQLEXPRESS服务器,并将所有内容存储在那里。

Here is my schema: 这是我的架构:

public class UserContext : DbContext {
    public UserContext() : base("name=BuddyDatabase") {

    }
    public DbSet<User> Users { get; set; }
    public DbSet<Message> Messages { get; set; }
}

public class User {
    [Key]
    public string username { get; set; }
    public string password { get; set; }

    public static implicit operator User(bool v) {
        throw new NotImplementedException();
    }

    public virtual List<User> friends { get; set; }
}

public class Message {
    [Key]
    public int ID { get; set; }

    public virtual User sender { get; set; }
    public virtual User recipient { get; set; }

    public string content { get; set; }

    public virtual List<User> group { get; set; }
}

Pretty simple 很简单

Sending messages to a single recipient works but group messaging doesn't, whenever I open the "Messages Screen" I get this error: 将消息发送给单个收件人有效,但是组消息传递无效,每当我打开“消息屏幕”时,都会出现此错误:

Unable to create a constant value of type 'WindowsFormsApp1.User'. 无法创建类型为“ WindowsFormsApp1.User”的常量值。 Only primitive types or enumeration types are supported in this context. 在此上下文中仅支持原始类型或枚举类型。

And this is the method I have run when the Message Screen loads up: 这是我在消息屏幕加载时运行的方法:

var x = db.Messages.Where(b => b.recipient.username == currentuser.username);
foreach (var y in x) {
    MainMessagesBox.Text += y.content;
}
x = null;

var z = db.Messages.Where(b => b.group.Contains(currentuser));
foreach (var y in z) {
    MainMessagesBox.Text += y.content;
}

(Visual Studio highlights the 'in' in this line as the cause of the error.) (Visual Studio突出显示此行中的“ in”作为错误原因。)

foreach (var y in z) { foreach(z中的y){

Thought this might be a problem with me using the Where method and involving non-primitives (as the error message suggests) so I tried changing my schema so that group is a list of strings that contain the usernames of the intended recipients and modified the methods accordingly but that didn't work either. 我以为这可能是我使用Where方法并涉及非基本元素的问题(如错误消息所暗示的),所以我尝试更改架构,以便该组是包含目标收件人的用户名的字符串列表,并修改了方法因此,但这也不起作用。 Will provide code and errors for that trial on request. 将根据要求提供该试用版的代码和错误。

Here is the actual "Send Message" code: 这是实际的“发送消息”代码:

if (!textBox1.Text.Contains(',')) {
    db.Messages.Add(new Message { sender = currentuser, recipient = db.Users.Find(textBox1.Text), content = currentuser.username + ": " + ContentBox.Text + "\n" });
    db.SaveChanges();
} else {
     List<User> recips = new List<User>();
     string[] poop = textBox1.Text.Split(',');

     foreach (var x in poop) {
         recips.Add(db.Users.Find(x));
     }

     db.Messages.Add(new Message { sender = currentuser, group = recips, content = ContentBox.Text });
     db.SaveChanges();
}

poop is an array of the intended recipients separated by comma from a textbox, this is temporary. poop是由文本框中的逗号分隔的预期收件人的数组,这是临时的。

Sorry if anything is misformatted or I'm unclear, this is my first question. 抱歉,如果格式错误或不清楚,这是我的第一个问题。

Thank you in advance. 先感谢您。

The problem is the Select query on message table where you check for the current user to be in the group list. 问题是在消息表上选择查询,您在其中检查当前用户是否在group列表中。 This won't work, because the query has to be translated to SQL to be send to the database. 这将不起作用,因为查询必须转换为SQL才能发送到数据库。

SQL does not understand what a ´User´ type is and can't compare references. SQL无法理解“用户”类型是什么,因此无法比较引用。 And actually, neither does C# compare this properly. 实际上,C#都没有对此进行正确比较。 Two objects of type ´User´ with the same username would not be equal in your case. 在您的情况下,具有相同username两个“ User”类型的对象将不相等。 You need to compare the username of those objects. 您需要比较那些对象的用户名。

Regardless, as Bitmask explained in a comment, you have to properly define the foreign key for the messages. 无论如何,正如Bitmask在评论中解释的那样,您必须正确定义消息的外键。

It's quite easy for the sender of the messages. 发送消息的人很容易。 You have a public virtual ICollection<Message> Messages { get; set; } 您有一个public virtual ICollection<Message> Messages { get; set; } public virtual ICollection<Message> Messages { get; set; } public virtual ICollection<Message> Messages { get; set; } in your User class. public virtual ICollection<Message> Messages { get; set; }在您的User类中。

But for the recipients, it's a many-to-many relation. 但是对于接收者来说,这是一个多对多的关系。 So both, the User class and the Message class have a collection to Message and User respectively. 因此, User类和Message类都分别具有MessageUser的集合。

Something like this should work: 这样的事情应该起作用:

public class User {
    [Key]
    public string username { get; set; }
    public string password { get; set; }

    public static implicit operator User(bool v) {
        throw new NotImplementedException();
    }

    public virtual ICollection<Message> SentMessages { get; set; }
    public virtual ICollection<Message> ReceivedMessages { get; set; }

    public virtual List<User> friends { get; set; }
}

public class Message {
    [Key]
    public int ID { get; set; }

    public virtual User Sender { get; set; }
    public virtual ICollection<User> Recipients { get; set; }

    public string content { get; set; }
}

Check this link for an example on how to define a many-to-many relation either using data annotations or fluent API. 查看此链接,获取有关如何使用数据注释或流利的API定义多对多关系的示例。 This assumes you're using EF6 though. 前提是您使用的是EF6。 If you're using an older version of EF, you might have to define the joining table yourself to get the many-to-many relation. 如果您使用的是EF的旧版本,则可能必须自己定义联接表才能获得多对多关系。

And as for the query. 至于查询。 You can use the following in your message screen OnLoad method: 您可以在消息屏幕的OnLoad方法中使用以下命令:

MainMessagesBox.Text = string.Join(System.Environment.NewLine, currentuser.ReceivedMessages.Select(m => m.content))

This concatenates all messages, separated with a new line. 这会连接所有消息,并用新行分隔。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM