c# - EF 只包含一次嵌套实体
问题描述
实体框架不会多次包含嵌套实体及其数据。
以下是邮递员的回复:
[{
"ProjectID": 29,
"ProjectName": "Angular",
"ProjectDescription": "This is angular project for developing webpages.",
"ProjectURL": "angular.com",
"ApplicationEntity": [],
"ApplicationID": 21
},
{
"ProjectID": 30,
"ProjectName": "Dot Net 6",
"ProjectSlug": "MAUI",
"ProjectDescription": "This is project for .net framwork MAUI.",
"ProjectURL": "maui.com",
"ApplicationEntity": [
{
"ApplicationID": 21,
"ApplicationName": "Custom Application",
"ApplicationVersion": "1.0.0.0",
"ApplicationDescription": "This is for a custom implementation."
}
],
"ApplicationID": 21
}]
如您所见"ApplicationID" : 21
,两个条目中的内容相同。但是ApplicationEntity
不包括它的值"ProjectID":29
。
创建项目.cs
public ProjectEntity CreateProject(int id, ProjectEntity projectEntity)
{
projectEntity.ApplicationID = id;
CustomerSupportDBContext dBContext = new CustomerSupportDBContext();
ApplicationEntity applicationEntity = dBContext.ApplicationEntities.SingleOrDefault(e => e.ApplicationID == id);
using (dBContext)
{
projectEntity.ApplicationEntity.Add(applicationEntity);
dBContext.ProjectEntities.Add(projectEntity);
dBContext.SaveChanges();
}
return projectEntity;
}
编辑: ProjectController.cs
[Route("getAllProjects")]
[HttpGet]
public HttpResponseMessage GetAllProjects()
{
try
{
ProjectService projectService = new ProjectService();
IQueryable<ProjectEntity> response = projectService.GetAllProjects();
return Request.CreateResponse(HttpStatusCode.OK, response);
}
catch (Exception ex)
{
return Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message + " " + ex.StackTrace);
}
}
项目服务.cs
public IQueryable<ProjectEntity> GetAllProjects()
{
CustomerSupportDBContext dBContext = new CustomerSupportDBContext();
var projectEntities = dBContext.ProjectEntities.Include("ApplicationEntity");
return projectEntities;
}
项目实体.cs
[Table("ProjectEntity")]
public class ProjectEntity
{
[Key]
public int ProjectID { get; set; }
public string ProjectName { get; set; }
public string ProjectDescription { get; set; }
public string ProjectURL { get; set; }
public List<ApplicationEntity> ApplicationEntity { get; set; }
public int ApplicationID { get; set; }
public ProjectEntity()
{
ApplicationEntity = new List<ApplicationEntity>();
IssueEntity = new List<IssueEntity>();
}
}
应用实体.cs
[Table("ApplicationEntity")]
public class ApplicationEntity
{
[Key]
public int ApplicationID { get; set; }
public string ApplicationName { get; set; }
public string ApplicationVersion { get; set; }
public string ApplicationDescription { get; set; }
}
数据库上下文.cs
public class CustomerSupportDBContext : DbContext
{
public DbSet<ProjectEntity> ProjectEntities { get; set; }
public DbSet<ApplicationEntity> ApplicationEntities { get; set; }
public CustomerSupportDBContext()
{
Configuration.LazyLoadingEnabled = false;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
只有最后一个实体ApplicationEntity
拥有它的详细信息。
解决方案
您的实现中有很多错误,我怀疑您的映射正在做一些非常奇怪的事情,以使事情看起来像是工作。
明显的问题是您在 Project 和 Application 之间定义一对多关系,其中 ProjectEntity 包含 ApplicationEntity 的集合,但是您在实体中的 FK 关系是向后的。ApplicationEntity 应该有一个 ProjectId 而不是 ProjectEntity 有一个 ApplicationId。我将首先仔细查看您生成的架构,以确定这些数据行使用什么以及如何相互链接。
如果 Project 有 0-1 Application,则 ProjectEntity 将有一个可为空的 ApplicationId 列,但将包含一个 ApplicationEntity 引用,而不是一个List<ApplicationEntity>
. 如果一个项目可以有 0 个应用程序,那么 ProjectEntity 将有List<ApplicationEntity>
但没有 ApplicationId,相反,ApplicationEntity 将有一个 ProjectId 作为 FK 映射回项目。
其他问题:
不要这样做:
CustomerSupportDBContext dBContext = new CustomerSupportDBContext();
var projectEntities = dBContext.ProjectEntities.Include("ApplicationEntity");
return projectEntities;
做这个:
using (CustomerSupportDBContext dBContext = new CustomerSupportDBContext())
{
var projectEntities = dBContext.ProjectEntities.Include("ApplicationEntity");
return projectEntities;
}
同样,不要这样做:
CustomerSupportDBContext dBContext = new CustomerSupportDBContext();
ApplicationEntity applicationEntity = dBContext.ApplicationEntities.SingleOrDefault(e => e.ApplicationID == id);
using (dBContext)
{
// ...
利用:
using (CustomerSupportDBContext dBContext = new CustomerSupportDBContext())
{
ApplicationEntity applicationEntity = dBContext.ApplicationEntities.SingleOrDefault(e => e.ApplicationID == id);
// ....
}
如果项目不使用依赖注入来管理其生命周期范围,请始终确保释放 DbContext。这将破坏您的IQueryable
实现,因为 DbContext 将在方法返回之前被释放。但是,像这样打开 DbContext 只是在寻找内存/数据库连接句柄泄漏的麻烦。
IQueryable<TEntity>
对于存储库来说是一种非常灵活和强大的模式,但它只能在 DbContext 生命周期范围超出返回IQueryable
. 利用依赖注入使调用者和存储库可以共享相同的 DbContext 实例,并且DbContext将保证在请求结束时被释放,或者使用存储库/服务可以的 DbContext 的工作单元包装器用于解析 DbContext 的实例。
具有工作范围单元的示例更像是:
using (var unitOfWork = ContextScopeFactory.Create())
{
var project = ProjectService.GetProjectById(projectId)
.Select(p => new ProjectViewModel
{
// populate details about project and application(s) that View needs
}).Single();
return project;
}
ProjectService 有一个 DbContext 解析器,用于从包装上下文范围获取 DbContext 引用。这是一个更高级的示例,它可以让调用者利用IQueryable
. 在您的实现中,您不能依赖做任何事情,IQueryable
因为 DbContext 引用被挂起,并且当有人去修复内存泄漏或从未处理的 DbContext 打开 DB 连接泄漏时,该方法将失败。(也可以返回IEnumerable<ProjectEntity>
。
推荐阅读
- json - 何我可以使用 G-sheets 中应用的超链接和样式获取数据并使用 JSON url 显示
- c# - 将虚假数据添加到列表
- ios - URLSessionWebSocketTask:致命错误:只有消息或错误之一应为 nil
- docker - 有没有快速查看.dockerignore效果的命令?
- java - Java 11 中的 Jasperreport。java.lang.NoClassDefFoundError: 无法初始化类 net.sf.jasperreports.engine.util.JRStyledTextParser
- node.js - 使用代理传递 apache 的 https 域上的套接字 io
- github - 如何更改 github 拉取请求的默认标题
- r - 在 Shiny DT 中,当有很多 ScrollX=TRUE 的列时,焦点会丢失
- php - 如何通过 Laravel Query builder 制作 sql foreach 循环?
- python - 尝试在 Windows 上安装 opencv-python 时出错