【发布时间】:2016-03-08 01:10:27
【问题描述】:
因此,我正在开展一个项目,该项目包含一个集中的通信页面,其中包含来自整个站点的所有“注释”。现在我可以在每个模型的基础上带入笔记,但我被三个组困住了,它们不仅需要笔记,还需要按父级划分,以便将每组笔记分配给适当的父母。
作为一个快速细分:
最高层是公司。公司内部的几个部分可以有自己的笔记(多个笔记,所以每个部分都有单独的笔记表),因此从这个级别引入了几个笔记表。
下一个层次是公司可以经历的“循环”。只有最近的周期才会得到处理,所以这最终变得相当简单。此级别包含带有单独注释表的大多数部分,但是通过将当前周期包含在声明中,我可以仅过滤当前周期。
最低级别涉及一些挂起循环的表。由于这些不像循环那样受到限制,因此我不仅需要能够引入这些表格,还需要能够引入这些表格中每个条目的注释。虽然可以通过 Cycle 声明过滤表格,但 notes 表格没有这些信息。
我的问题在于这个最低级别。我不知道如何创建一个“多 IEnumerable”,以便父数据和子数据都可以附加到单个 viewModel 容器。这使我无法创建可以填充该容器的 Linq Lambda 表达式。一旦我装满了容器,剩下的就应该很容易了——我只需要创建一对嵌套的 for 循环,它们首先提取父级(只是表格行的名称)和子级(来自注释的所有注释条目该表行的表)。
换句话说,我需要一个左连接来填充单个视图模型,并且我无法做到这一点,直到我知道如何创建一个包含两个模型的 IEnumerable。
Parent
+----+------+
| id | name |
+----+------+
| 1 | John |
| 2 | Mike |
-------------
Child
+----+-----+-----------------+------------+
| id | Pid | note | date |
+----+-----+-----------------+------------+
| 1 | 2 | Mike's notes | 2016-01-15 |
| 2 | 1 | John’s notes | 2016-02-22 |
| 3 | 2 | More Mike’s | 2016-02-24 |
| 4 | 2 | Yet more Mike’s | 2016-03-01 |
-------------------------------------------
Page output
John
2016-02-22 John’s Notes
[text field] [submit]
Mike
2016-01-15 Mike’s notes
2016-02-24 More Mike’s
2016-03-01 Yet more Mike’s
[text field] [submit]
另外,请记住,这只是被引入页面的众多模型之一,现在我在同一页面上有将近 20 个,所以我的控制器以 var viewModel = new CommunicationsViewModel(); 开头并引入了多个模型通过控制器模型中的 IEnumerables 将它们附加到viewModel。我唯一的问题是我需要将两个模型附加到一个 IEnumerable,以便我的 JOIN 查询可以成功地将内容转储到 viewModel 容器中。
现在,我最有希望的 Lambda 表达式是:
viewModel.Active = await db.Activity
.Join(
db.ActivityNotes.Include(y => y.NotesStatus),
act => act.ActivityId,
actnot => actnot.ActivityId,
(act, actnot) => new { Activity = act, ActivityNotes = actnot }
)
.Where(act => act.CycleId == cycleId)
.ToListAsync();
当然,在我弄清楚如何将 Activity 和 ActivityNotes 组合成一个名为 Active 的单个 IEnumerable 之前,我无法对它做任何事情。
编辑:致埃里克·飞利浦:
对于我的通讯页面,我制定了以下模型:
public class CommunicationsViewModel {
...more IEnumerated models...
public IEnumerable<Activity> Active { get; set; }
public IEnumerable<ActivityNotes> ActiveComm { get; set; }
}
注意最后两个条目,父项和子项。父节点需要为循环 Guid 过滤,仅此而已。
我的 OnModelCreating:
#region Activity
modelBuilder.Entity<Activity>().HasMany(x => x.ActivityNotes).WithRequired(x => x.Activity).HasForeignKey(x => x.ActivityId).WillCascadeOnDelete(true);
modelBuilder.Entity<Activity>().HasKey(x => x.ActivityId);
modelBuilder.Entity<Activity>().Property(x => x.ActivityId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Activity>().Property(x => x.CycleId).IsRequired();
modelBuilder.Entity<Activity>().Property(x => x.ActivityName).HasColumnType("nvarchar").HasMaxLength(50).IsOptional();
modelBuilder.Entity<Activity>().Property(x => x.ActivityDate).HasColumnType("date").IsRequired();
... redundant content removed ...
#endregion
#region ActivityNotes
modelBuilder.Entity<ActivityNotes>().HasKey(x => x.ActivityNotesId);
modelBuilder.Entity<ActivityNotes>().Property(x => x.ActivityNotesId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<ChampionNotes>().Property(x => x.Notes).IsRequired();
#endregion
我的索引,高度删节,仅包含相关部分:
public async Task<ActionResult> Index() {
var cycleId = new Guid(User.GetClaimValue("CWD-Cycle"));
var viewModel = new CommunicationsViewModel();
viewModel.Active = await db.Activity.Where(x => x.CycleId == cycleId).Where(x => x.Active == true).ToListAsync();
...more viewModelled content brought in...
return View(viewModel);
}
还有我观点的内容:
@foreach(var item in Model.Active) {
@Html.DisplayFor(modelItem => item.ActivityName)
foreach(var subItem in Model.ActiveComm) {
@Html.DisplayFor(modelItem => subItem.Notes)
}
}
…啊,它在第二个foreach 上基本上失败了,经典的“对象引用未设置为对象的实例”。这对于 ASP.NET 来说是个通俗易懂的说法:“哎呀,你真搞砸了;祝你好运找到哪里。”
【问题讨论】:
-
如果你告诉 EF 有一个 foreign key and setup navigation properies...
-
我非常小心地在 EF 6 和 Fluent Validation 中包含外键引用。这意味着我的代码优先数据库具有完整的关系,所有关系都根据需要具有适当的级联/忽略设置。所以你的意思是我所要做的就是引入我的活动,然后执行双重
for循环以吐出按活动分组的笔记?不知何故,这听起来不对;设置中应该涉及更多工作,以便注释可以明确地定位在其for循环中。
标签: asp.net-mvc linq asp.net-mvc-5 entity-framework-6