所以我正在开发一个包含集中通信页面的项目,该页面包含整个站点的所有“注释”。现在我能够在每个型号的基础上提供笔记,但是我被困在三组不仅需要笔记,而且需要被父母划分,以便每组笔记被分配到正确的父节点。
快速细分:
最高级别是公司。公司内部的几个部分可以有自己的注释(多个注释,每个部分都有单独的注释表),因此从这个级别引入了几个注释表。
下一个级别是公司可以经历的“周期”。只有最近的周期才会得到处理,所以最终会变得相当简单。此级别包含大多数具有单独注释表的部分,但通过将当前周期包含在声明中,我可以仅过滤当前周期。
最低级别涉及几个挂起循环的表格。由于它们不像循环那样受限制,我需要不仅能够引入这些表,还需要引入这些表中每个条目的注释。虽然这些表可以通过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();
开始并且有多个模型通过在Controller的模型中通过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之前,我当然无法做任何事情。
编辑:对于Erik Philips:
对于我的通讯页面,我列出了以下模型:
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)
}
}
... Aaaand它基本上在第二个foreach
失败,经典的“对象引用未设置为对象的实例”。这对于ASP.NET说“哎呀,你痴迷”;祝你好运,找到了。“
答案 0 :(得分:2)
我不知道如何创建“多IEnumerable”,以便父数据和子数据都可以附加到单个viewModel容器。
我根本不理解这句话......这是一个包含父模型和子模型的ViewModel:
public class MyModel
{
public IEnumerable<Parent> Parents { get; set; }
public IEnumerable<Child> Children { get; set; }
}
虽然下面的内容似乎与您想要的一样,但仍然很简单。
public class MyModel
{
public IEnumerable<Parent> Parents { get; set; }
}
public class Parent
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Child> Children { get; set; }
}
public class Child
{
public int Id { get; set; }
public int Pid { get; set; }
public Parent Parent { get; set; }
public string Note { get; set; }
public DateTime Date { get; set; }
}
public class MyDbContext : DbContext
{
public override void OnModelCreating(DbModelBuilder mb)
{
mb.Entity<Parent>()
.HasKey(p => p.Id);
mb.Entity<Child>()
.HasKey(c => c.Id)
.HasRequired(c => c.Parent)
.WithMany(p => p.Children)
.HasForeignKey(c => c.Pid);
}
}
public ActionResult SomeMethod()
{
var viewModel = new MyModel
{
Parents = db.Set<Parent>()
.Where(p => p.Id == 1)
.Include(p => p.Children)
.AsNoTracking()
.ToList();
};
return View(viewModel);
}
对象引用未设置为对象的实例“。这对于ASP.NET说“哎呀,你痴迷”;祝你好运,找到了。“
不,它只意味着一件事,它总是意味着同样的事情。这意味着您要求RunTime Engine访问从未赋值(most of the time it's the programmers error)的变量。
你有这个模特:
public class CommunicationsViewModel {
public IEnumerable<Activity> Active { get; set; }
public IEnumerable<ActivityNotes> ActiveComm { get; set; }
}
并且您提供的唯一代码是:
viewModel.Active = await db.Activity
.Where(x => x.CycleId == cycleId)
.Where(x => x.Active == true)
.ToListAsync();
所以非常显然你永远不会设置:
Model.ActiveComm
这是我对这篇文章的最后一次编辑。你缺少基本的c#理解和基本的调试技巧。我建议您花一些时间来审核http://www.asp.net/web-pages/overview/testing-and-debugging/introduction-to-debugging以及http://www.asp.net处提供的其他资源。祝你好运!
答案 1 :(得分:0)
我刚刚发现,关键在于如何将两个foreach
循环链接在一起,以及如何引入特定的数据块。
首先,只查看父级,但包含子级:
viewModel.Parent = await db.Parent
.Where(x => x.ForeignKey == limitingFactor)
.Include(x => x.Child)
.ToListAsync();
指出:只有父级必须以IEnumerable
的形式存在于页面的ViewModel中,这是我可怕地挂起来的 - 我认为两者都必须被引入。它们不会。由于我们只是明确地将父母带入viewModel
,如上所示,任何子内容都通过.Include()
骑在父母的尾巴上(以形成隐喻)。它们根本不需要在页面的ViewModel中作为IEnumerable
引用。
这就是Erik Philips在上面的帖子中所说的,完全归因于Erik在ActionResult
指出了这一点。然而,在这一点上,我仍然不知道如何在每个父母的基础上“抓住”儿童数据...因为我可以告诉它没有被带入。但是,当我看到我的观点时,我偶然发现穿过正确的方法。
纯粹的机会,我在第一个循环中建立了第二个foreach
循环,并且它有效。
第一个,外面的一个是父母:
@foreach(var parent in Model.Parent){
@Html.DisplayFor(modelItem => parent.RandomFieldNameInParent)
因为每个父母都需要有一个孩子的清单:
foreach(var child in parent.Child){
注意子表是如何被引入的?我们已经过滤了父项,到此时我们只查看一个父项,并且在这个内部foreach
循环中,我们正在寻找子表中与该父项相关的所有子项。这就是原因parent.Child
,而不是Model.Child
。它是来自外部foreach
循环的父级内容(任意数量的子级)。
结果代码如下所示:
@foreach(var parent in Model.Parent){
@Html.DisplayFor(modelItem => parent.RandomFieldNameInParent)
foreach(var child in parent.Child){
@Html.DisplayFor(modelItem => child.RandomFieldNameInChild)
}
}
这正是我从一开始就寻找的最终结果。请原谅我,我要自己倒一个僵硬的人;答案的简单性与找到它的努力完全不成比例。