对实现投票系统的关系进行建模

本文关键字:关系 建模 系统 实现 | 更新日期: 2023-09-27 17:54:11

我对投票系统的实现感到困惑。我想知道一个帖子的投票赞成和投票反对的计数,也保存投票赞成或反对的选民。我使用下面的模型

public class Post : Entity
{
    public string Title { get; set; }
    public virtual User Owner { get; set; }
    public virtual List<User> UpVoters { get; set; }
    public virtual List<User> DownVoters { get; set; }
}

我觉得这个设计有点问题,因为如果我必须表示一个帖子的投票和投票计数,所以我认为我必须处理2个查询。使用导航属性计数会导致性能问题,如果我只是需要计数。我说的对吗?

下面的第二种方法也让我感到困惑,因为VoteUpCount和VoteDownCount应该总是由开发人员手动处理。当选民改变他的投票时,总是重新更新值,这看起来有点代码味。

public class Post : Entity
{
    public string Title { get; set; }
    public virtual User Owner { get; set; }
    public int VoteUpCount { get; set; }
    public int VoteDownCount { get; set; }
    public virtual List<User> UpVoters { get; set; }
    public virtual List<User> DownVoters { get; set; }
}
你能告诉我哪个更好吗?为什么更好呢?我还有别的选择吗?

最后一个帖子持有3用户导航属性,这让我觉得有些东西可能是错误的。这段关系有什么问题吗?

对实现投票系统的关系进行建模

本能地,我将创建一个Vote实体,因为您想保存有关投票的信息:

public class Vote : Entity
{
    public User User {get;set;}
    public int VoteDirection {get;set;} // 1 or -1
    // any other info...
}

然后在Post类中添加Vote字段:

public class Post : Entity
{
    public string Title { get; set; }
    public virtual User Owner { get; set; }
    public virtual List<Vote> Votes { get; set; }
}

然后计算每个Votes的VoteDirection的总和…

我不认为这里有什么问题。

我看你的第一个模型还不错。除非您能证明获取相关实体的计数会影响性能,否则我不会采用第二种方法。过早优化是万恶之源;-)。

如果出于性能原因需要存储计数,那么第二个模型也可以。只需确保添加投票更新了count字段。

你的第一个模型是正确的,你不应该为了EF的缺点而牺牲你的模型,而且第二个版本不是很可维护——有太多的思考和手工工作。

当您想要检索计数时,实际上有一个EF物化所有相关实体的解决方案,语法不是很直观,但确实会产生正确的SQL查询:

var myPost = context.Posts.First();
int upvotersCount = context.Entry(myPost)
                           .Collection(p => p.UpVoters)
                           .Query()
                           .Count();

详细说明如下。

作为一般的经验法则,您应该在模型中使用ICollection<User>而不是具体的List<User>

Using navigation properties counts would cause performance problems if i just need counts. Am i right? -您心中有什么样的性能问题?

通常,添加count字段会在数据库中引入冗余,但这是一个明显的性能优化步骤。如果我是你,我会问自己在这种情况下是否需要提高表现。有多少帖子和投票将在数据库中?有多少用户将同时访问这些信息?等。如果您的应用程序需要真正的可伸缩,您可以添加额外的计数,并确保它们被正确更新。否则,你只需要记住这种可能性,而不是急于实现它。