筛选集合的子对象

本文关键字:对象 集合 筛选 | 更新日期: 2023-09-27 17:57:11

首先,我首先是EF代码和.NET的新手。

我正在开发一个移动Web应用程序,该应用程序是用MVC4,EF,JQuery,AutoMapper和其他技术和库构建的。

这可能会令人困惑,但我会尽力解释它。

我有以下 pocos:

  public class Test
{
    [Key]
    public int TestId { get; set; }
    .
    .
    Other properties
    .
    .
    public virtual ICollection<Question> Questions { get; set; }
    public virtual ICollection<UserStatus> UserStatuses { get; set; }
}
public class UserStatus
{
    [Key]
    public int UserStatusId { get; set; }
    public int TestId { get; set; }
    public string Customer { get; set; }
    .
    .
    Other properties
    .
    .
}
public class Question
{
    [Key]
    public int QuestionId { get; set; }
    public int TestId { get; set; }
    .
    .
    Other properties
    .
    .
}

在我的上下文类中,我有:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    Database.SetInitializer<CmeContext>(null);
    modelBuilder.Entity<Test>()
        .HasKey(a => new { a.TestId })
        .HasMany(s => s.Questions);
    modelBuilder.Entity<Test>()
        .HasKey(a => new { a.TestId })
        .HasMany(s => s.UserStatuses);          
}

上述测试对象通过 TestId 与问题和用户状态对象具有一对多关系。每个测试都有自己的一组问题,每个测试有 4 个问题,每个问题 20 个用户状态 5 个)。顾名思义,用户状态表具有用户状态;它让我知道用户回答了哪个测试中的哪些问题。

控制器中的代码:

var filtered = (from test in _ctxCmeContext.Test.Include("UserStatus").Include("Question")
                where test.Program == "SomeProgram" && test.IssueDate.Value.Year == year && test.IssueDate.Value.Month == monthNumber 
                orderby test.IssueDate descending 
                select new { test,
                                                 Questions = test.Questions, 
                         UserStatuses =     test.UserStatuses.Where(x => x.Customer == currentUserId) });

如您所见,我有一个匿名类,因此我可以获取按当前用户 ID 过滤的 UserStatuses 集合,以仅获取当前用户的状态。在这一点上一切正常。

这是我需要做的:

每个问题都需要知道自己的状态,因此它是问题和用户状态表之间的一对一关系

在我的上下文类中,我添加了以下内容:

      modelBuilder.Entity<Question>()
     .HasRequired(x => x.UStatus)
     .WithOptional();

在问题对象中,我有:

                        public virtual UserStatus UStatus { get; set; }

并且我还修改了我的linq语句,如下所示:

          var filtered = (from test in         _ctxCmeContext.Test.Include("UserStatus").Include("Question").Include("UStatus")
                where test.Program == "SomeProgram" &&   test.IssueDate.Value.Year == year && test.IssueDate.Value.Month == monthNumber 
                orderby test.IssueDate descending 
                select new { test, 
                             QuestionStatus =    test.Questions.Select(u=>u.UStatus), 
                             Questions = test.Questions, 
                             UserStatuses = test.UserStatuses.Where(x => x.Customer == currentUserId) }); 

结果:

UStatus 属性有每个问题的数据,但它不是针对当前用户的数据,也不是针对正确测试的数据;在我看来,它只是从问题表中抓取了它所反驳的第一条具有相同 QuestionId 的记录。白搭。

所以我将关系更改为一对多:

在我的上下文类中,我替换了:

    modelBuilder.Entity<Question>()
       .HasRequired(x => x.UStatus)
       .WithOptional();

跟:

        modelBuilder.Entity<Question>()
           .HasKey(a => new { a.QuestionId })
           .HasMany(s => s.UStatus);

将问题对象中的 UStatus 属性更改为:

   public virtual ICollection<UserStatus> UStatus { get; set; }

并从 LINQ 语句中删除了以下内容

   QuestionStatus = test.Questions.Select(u=>u.UStatus), 

这次我能够获得一些正确的数据,但仅适用于前 4 个问题,其余的为空

我不知道该怎么办了。请帮帮我。

筛选集合的子对象

通过您提供的 Schema/POCO 并分析您的故事,我可以总结如下:

You want to identify, which question(s) from what test was answered by a user?

如果这是你的意思,那么通过假设lazy loadingenabled in your context我可以建议一个类似于这样的查询:

var questions = context.Questions.Where( q => q.Test.Program == "someProgram" 
                && q.Test.UserStatus.Any( us => us.UserId == currentUserId ));

它执行以下操作:

  1. 过滤属于测试someProgram的问题
  2. 并具有用户UserStatus currentUserId
  3. 获取满足此条件的问题。

因此,在questions集合中,您可以找到问题的答案。

我对你的问题的理解可能是错误的,但我相信它为你提供了一些提示。

在 Question 对象中,我创建了一个返回到 Test 对象的导航属性,从那里我能够知道每个问题的状态,因为 UserStatus 是 Test 对象中的一个子集合。