【问题标题】:Filter Child Object of a Collection过滤集合的子对象
【发布时间】:2013-01-17 10:46:00
【问题描述】:

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

我正在开发一个使用 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);          
}

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

控制器中的代码:

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

如您所见,我有一个匿名类,因此我可以获取由 currentUserId 过滤的 UserStatuses 集合,以仅获取当前用户的状态。此时一切正常。

这是我需要做的:

每个问题都需要知道自己的状态,所以 Question 和 UserStatus 表之间是一对一的关系

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

      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 属性包含每个问题的数据,但不是针对当前用户,也不是针对正确的测试;在我看来,它只是从 Question 表中抓取了它遇到的第一个具有相同 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 个问题,其余的都是空的

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

【问题讨论】:

  • 请尽量用简短甜美的方式解释,以便问题得到更多关注。你写的越多,它获得的关注就越少。只需解释what you havewhat you want 以及您的研究工作(这个您可以用文字描述)。
  • 我只是在解释我拥有什么、我做了什么以及我想要完成什么。我想要做的就是使用相同的过滤 UserStatus 集合,以便每个问题都知道它的状态。
  • 我想指出的是,只把对读者绝对必要的东西放在你的问题中。例如:您提供了有关您的 re-factoring 的信息,这只会增加问题的大小,但不值得写。从心理上讲,人们懒得去读那些不值得读的东西。但是,我试图最好地回答我的水平。请检查一下。
  • 在空格上放轻松...它不会使其更具可读性。只是需要更多的鼠标滚轮。

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


【解决方案1】:

通过您提供的 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. 并且拥有用户currentUserIdUserStatus
  3. 获取满足此条件的问题。

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

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

【讨论】:

  • 延迟加载已禁用 我不想只返回问题列表。我需要返回的列表是一个测试列表(假设 1 个测试)一个测试有 2 个集合(UserStatus(由当前用户过滤的 4 条记录)和问题(每个测试 4 个问题,每个问题需要从相同的过滤用户状态列表))。我希望这会有所帮助。
  • 好吧,在这种情况下,Test 应该包含所有相关的QuestionsUserStatus,当被context.Tests.Where( t =&gt; t.UserStatus.UserId == currentUserId) 这样的用户过滤时。为了简单起见,我在启用延迟加载的情况下编写了答案。
  • 那不是我要找的东西,但还是谢谢你。我只是采取了不同的方法并让它发挥作用。
  • 请将它作为答案发布并接受它,以便其他人从中受益。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-30
    • 1970-01-01
    相关资源
    最近更新 更多