【发布时间】:2021-12-27 13:32:19
【问题描述】:
好的,大家好。我已经盯着这个看了好几个小时了,我觉得我快疯了。我知道这有点,很抱歉它太长了,我试图让它尽可能容易地流动,但是呃……让我把 tl;dr 放在前面。
tl;dr:对两个对象(EF Core 中的“实体”)进行相同的处理,但由于某种原因,它们的处理方式有所不同,这给了我一个非常烦人的错误。什么给了?
好的,首先我使用的是 Entity Framework 6.4.4、EntityFrameworkCore.Sqlite 和 EntityFrameworkCore.Tools 3.1.4、Visual Studio 16.10.0 和 .NET Core 3.1,但是,出于稍后您会看到的原因,我真的不认为这是相关的。我只是把它包括在内。
所以,这会有点,但我会尽量保持简单。我在访问数据时遇到问题,我不知道为什么。让我从我的模型开始。我将包括三个(并简化它们)
MyNamespace/Models/Project.cs
namespace MyNamespace.Models
{
public class Project
{
public int ID { get; set; }
// Bunch of other stuff, doesn't matter
public ICollection<Comment> Comments { get; set; }
public ICollection<MyNamespace.Models.File> Files { get; set; }
// Yes I'm intentionally using the full path here because this is where the confusion is
}
}
MyNamespace/Models/Comment.cs
namespace MyNamespace.Models
{
public class Comment
{
public int ID { get; set; }
public int ProjectID { get; set; }
// Other attributes
public Project Project { get; set; }
}
}
MyNamespace/Models/File.cs
namespace MyNamespace.Models
{
public class File
{
public int ID { get; set; }
public int ProjectID { get; set; }
// Other attributes
public MyNamespace.Models.Project Project { get; set; }
// Again being very explicit here because I'm at a loss
}
}
你看到我在这里得到了什么,对吧? Project 实体可以包含零个或多个 cmets 以及零个或多个文件,并且每个注释或文件可以与一个项目相关联。这是我们正在研究的一对多关系。不是超级复杂,我还有其他具有类似关系的实体,一切都像我期望的那样工作,除了File 实体。我在这里包括Comment 实体来说明,据我所知,我正在正确对待File 实体,与Comment 实体相同,但我不知道为什么它不起作用.不过,请注意,还有其他实体我也在处理同样的事情并且工作正常。
所以这些是有问题的模型。这是我的DbContext
MyNamespace/Data/ProjectDBContext.cs
namespace MyNamespace.Data
{
public class ProjectDBContext : DbContext
{
public DbSet<Project> Projects { get; set; }
// Other stuff
public DbSet<Comment> Comments { get; set; }
public DbSet<MyNamespace.Models.File> Files { get; set; }
}
}
同样,我有很多东西,一切都按预期工作,直到我添加了这个新的 File 模型。
所以,既然我们已经完成了所有设置,让我们进入代码吧。
我知道,我的组织有点奇怪,(但我认为这有点合适?),但我将包括所有我认为相关的内容。我正在使用视图组件和 Razor 页面,所以,首先,我们有一个常规的 Razor 页面(如果你们真的想要它,我会包含 MyNamespace/Pages/Projects/View.cshtml.cs,但我真的不认为问题出在这里,所以我'现在要跳过它。)
MyNamepsace/Pages/Projects/View.cshtml
@model MyNamespace.Pages.Projects.View
<!-- Some stuff -->
<div>
@await Component.InvokeAsync("CommentsBox", Model.Project)
</div>
<div>
@await Component.InvokeAsync("FilesBox", Model.Project)
</div>
<!-- Other stuff -->
现在,我想澄清一下,Files 的东西不起作用。 Comments 的东西可以。我将两者都包括在内是为了说明它适用于一个而不是另一个,我不知道为什么。抱歉,我们的视图组件的第一部分。
MyNamespace/ViewComponents/CommentsBox.cs
namespace MyNamespace.ViewComponents
{
public class CommentsBox : ViewComponent
{
public IViewComponentResult Invoke(Project project)
{
return View("Default", project)
}
}
}
MyNamespace/ViewComponents/FilesBox.cs
namespace MyNamespace.ViewComponents
{
public class FilesBox : ViewComponent
{
public IViewComponentResult Invoke(Project project)
{
// We'll come back to this later, but I have a breakpoint set at this line.
return View("Default", project)
}
}
}
现在,观点(我实际上不知道当我称这些“观点”时我是否使用了正确的用语,但这不是重点)
MyNamespace/Pages/Shared/CommentsBox/Default.cshtml
@model MyNamespace.Models.Project
<!-- Some stuff -->
@foreach (var comment in Model.Comments)
{
// Just display info, this all works fine
}
<!-- Some stuff -->
MyNamespace/Pages/Shared/FilesBox/Default.cshtml
@model MyNamespace.Models.Project
<!-- Some stuff -->
@foreach (var file in Model.Files) // ERROR
{
// Supposed to display the info
}
<!-- Some stuff -->
<!-- Do note, there is some code here to upload a file. If I remove the code above that's throwing the error, It actually does upload the file. -->
所以我得到的错误是抱怨MyNamespace/Pages/Shared/FilesBox/Default.cshtml 中的for 循环,它是ArgumentNullException。它抱怨Model.Files 为空,所以我无法对其进行迭代。但这没有任何意义,(你会看到它有一点作用,但我不知道为什么它是null)。因为,对于我没有 cmets 和文件的项目,MyNamespace/Pages/Shared/CommentsBox/Default.cshtml 中的循环工作得很好。为什么它适用于 Comments 而不是 Files?
此外,如果我从 MyNamespace/Pages/Shared/FilesBox/Default.cshtml 中删除 for 循环并使用上传文件的代码来上传文件,它就可以正常工作。完全没有问题。现在,我们知道我们在与该项目关联的数据库中有一个文件。所以,只是为了好玩,让我们改变MyNamespace/Pages/Shared/FilesBox/Default.cshtml
MyNamespace/Pages/Shared/FilesBox/Default.cshtml
@model MyNamespace.Models.Project
<!-- Some stuff -->
@try
{
@foreach (var file in Model.Files)
{
// We should display info here
}
}
catch (Exception ArgumentNullException)
{
<text>Woops we've caught our exception</text>
}
<!-- Some stuff -->
<!-- Do note, there is some code here to upload a file. It actually does upload the file, if I remove the code above that's throwing the error -->
好的,所以我们知道我们在数据库中有一个文件,我可以在数据库中看到它(而不是在网页上),我可以看到它的 ProjectID 正是我所期望的。再次运行它,我们发现了我们的错误情况。为什么?我们知道我们在数据库中有一个文件,其中 ProjectID 指向我们的项目。请记住,我们对 cmets 没有这个问题。即使数据库中没有带有此ProjectID 的 cmets,我们也不会收到此错误。然而,即使我们确实在数据库中有一个文件,我们仍然会收到错误,我们甚至可以通过询问错误条件来确认。
好的,所以,我们知道数据库中有一个文件指向我们的项目,但我们仍在输入错误条件。我将MyNamespace/Pages/Shared/FilesBox/Default.cshtml 改回原来的,没有错误检查。数据库保留其信息,无需担心。但是我们又回到了同样的错误。它只是没有将File 实体与其正确的Project 实体相关联。
还记得那个断点吗?这就是事情变得好奇的地方。如果我检查从MyNamepsace/Pages/Projects/View.cshtml 到MyNamespace/ViewComponents/FilesBox.cs 到MyNamespace/Pages/Shared/FilesBox/Default.cshtml 的Project 对象,就在它转到MyNamespace/Pages/Shared/FilesBox/Default.cshtml 之前,我看到了一些有趣的东西。我们可以在运行时的那个时刻检查对象,并看到确实,我们的Project 对象的Files 属性是null,但是对于Comments?不是null,而是Count = 0...所以...为什么?我觉得我为他们俩做了完全相同的事情。我以相同的方式设置它们,在DbContext 中对它们进行相同处理,在模型中对它们进行相同处理,以及它们与Project 的关联。为什么会有不同的待遇?
此外,如果我们在该断点检查Project 对象,我们可以看到它的Comments 属性,其中值是Count = 0,类型是System.Collections.Generic.ICollection<MyNamespace.Models.Comment> {System.Collections.Generic.HashSet<MyNamespace.Models.Comment>}。但是,对于我们的Project 对象的Files 属性,其值为null(即使我们知道数据库中有ProjectID 指向该项目的文件),类型只是System.Collection.Generic.ICollection<MyNamespace.Models.File> .我什至尝试将模型MyNamespace/Models/Project.cs 更改为
MyNamespace/Models/Project.cs
namespace MyNamespace.Models
{
public class Project
{
public int ID { get; set; }
// Bunch of other stuff, doesn't matter
public ICollection<Comment> Comments { get; set; }
public HashSet<MyNamespace.Models.File> Files { get; set; }
// See? I'm specifying the HashSet type here
}
}
但是,无济于事。同样的错误,同样的行为。
我确定我缺少的东西都很小,但我一直在寻找这个,当我把这整件事写出来时,已经有一天多的时间了,我只是不知所措。它是 Visual Studio 的东西吗?我错过了什么吗?我只是不知道。我希望你们这些优秀的人能够看到我看不到的东西,或者能够为我指明正确的方向。
【问题讨论】:
标签: c# asp.net entity-framework razor