【问题标题】:EF includes nested entity only onceEF 只包含一次嵌套实体
【发布时间】:2021-07-29 09:35:18
【问题描述】:

实体框架不会多次包含嵌套实体及其数据。

以下是邮递员的回复:

[{
    "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 的值。

CreateProject.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);
        }
    }

ProjectService.cs

public IQueryable<ProjectEntity> GetAllProjects()
    {
        CustomerSupportDBContext dBContext = new CustomerSupportDBContext();
        var projectEntities = dBContext.ProjectEntities.Include("ApplicationEntity");
        return projectEntities;
    }

ProjectEntity.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>();
    }
}

ApplicationEntity.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; }
}

DbContext.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 及其详细信息。

【问题讨论】:

    标签: c# .net entity-framework asp.net-web-api


    【解决方案1】:

    ProjectEntity 上的 ApplicatonEntity 属性是一个列表。这意味着每个项目可以有多个应用程序。如果一个项目有多个应用程序,那么 ProjectEntity 上的 ApplicationId 的值是多少。我怀疑 ApplicationEntity 预计将链接到单个项目,因此只有最后一个项目会获取应用程序。我认为 ApplicationEntity 属性不应该是一个列表

    【讨论】:

      【解决方案2】:

      您的实现中存在许多问题,我怀疑您的映射正在做一些非常奇怪的事情以使事情看起来可以正常工作。

      明显的问题是您在 Project 和 Application 之间定义一对多关系,其中 ProjectEntity 包含 ApplicationEntity 的集合,但是您在实体中的 FK 关系是倒退的。 ApplicationEntity 应该有一个 ProjectId 而不是 ProjectEntity 有一个 ApplicationId。我将首先仔细查看您生成的架构,以确定这些数据行使用什么以及如何相互链接。

      如果 Project 有 0-1 个应用程序,则 ProjectEntity 将有一个可为空的 ApplicationId 列,但将包含单个 ApplicationEntity 引用,而不是 List&lt;ApplicationEntity&gt;。如果一个项目可以有 0 个应用程序,那么 ProjectEntity 将有 List&lt;ApplicationEntity&gt; 但没有 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&lt;TEntity&gt; 是一种非常灵活且功能强大的存储库模式,但它只能在 DbContext 生命周期范围超出返回 IQueryable 的方法时工作。利用依赖注入使调用者和存储库可以共享 DbContext 的同一实例 AND 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&lt;ProjectEntity&gt;

      【讨论】:

        猜你喜欢
        • 2020-10-01
        • 1970-01-01
        • 2017-08-31
        • 1970-01-01
        • 2017-11-27
        • 2011-11-02
        • 2013-03-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多