我的模型集合字段为空?

时间:2017-09-07 13:59:36

标签: c# asp.net-mvc entity-framework razor

我使用ASP.NET MVC Web应用程序来生成VSTS服务器的Back-Ups。

我的数据库有一堆嵌套表,在这种情况下,我正在访问一个名为" Project"的表。其中一个字段是ICollection,其中Backup是我的MVC中我的数据库/模型中的另一个表。项目在使用其中一个标准Controller模板创建的视图中加载得很好,但是,ICollection字段始终为null,即使有明确的"备份"在我的数据库中。

这是我的代码:

@model IEnumerable<Backup_Tool.Models.Site>

@functions{
    public string GetLatest(Backup_Tool.Models.Project projekt)
    {
        if (projekt.Backup == null)
            return "( - )";
        DateTime time = DateTime.Now.AddYears(-500);
        foreach (var back in projekt.Backup)
        {
            if (back.CreationTime > time)
                time = back.CreationTime;
        }
        return $"{time.ToShortDateString()}";
    } }
@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Uri)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.CreationTime)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Password)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.User)
        </td>
        <td>
            @foreach (var project in item.Projects)
            {
                <p>@Html.DisplayFor(m => project.Name)</p>
                <i>@GetLatest(project)</i>




            }
        </td>

我是否还需要在顶部添加备份模型?实际上使用数据库上下文加载备份?

1 个答案:

答案 0 :(得分:0)

没有您的实体类很难说,但很可能,您忽略了将virtual关键字添加到您的集合属性中,并且也未能急切地加载它。

virtual关键字是Entity Framework的延迟加载功能所必需的。 EF实际上创建了一个从您的实体类继承的代理类,然后覆盖导航属性以添加延迟加载逻辑。如果属性不是虚拟的,则不能覆盖它,因此无法添加必要的延迟加载逻辑。

但是,只是急切地加载集合,而不是依赖于延迟加载,这样做要好得多。虽然延迟加载很容易,但它也效率低下,并且经常导致逻辑错误不明显。例如,如果您执行此类操作,则会引发异常:

 using (var context = new MyDbContext())
 {
     var foo = context.Foos.ToList();
 }

 foreach (var bar in foo.Bars) // where `Bars` is a lazy-loaded collection
 {
     ...
 }

foreach已经处理了上下文时,所以当EF尝试加载集合以便迭代它时,它将失败。如果你刚刚看到这个代码,那么错误在哪里并不明显,如果你想要可维护的代码,这是一个非常重要的事情。

无论如何,为了急切地加载集合,只需在初始查询中使用Include即可。例如:

var project = context.Projects.Include(m => m.Backups).SingleOrDefault(m => m.Id == projectId);

注意,您必须使用SingleOrDefault之类的内容,而不是FindFind尝试在命中数据库之前首先从上下文缓存加载实体,因此逻辑与其他实体的加入不兼容。

最后,您的GetLatest功能既低效又多余。只需使用LINQ&#39; Max函数:

@foreach (var project in item.Projects)
{
    <p>@Html.DisplayFor(m => project.Name)</p>
    <i>@(project.Backups.Max(m => m.CreationTime).ToShortDateString())</i>
}

此外,当您按原样返回值时,请避免字符串插值。例如,此代码:

return $"{time.ToShortDateString()}";

应该简单:

return time.ToShortDateString();

最终结果是相同的,但您只需要向堆中添加一个字符串而不是两个。虽然这是一件相当小的事情,但这样的低效率可能会在您的应用程序中出现大问题。