Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Entity framework EF 4.3中的持续变更-变更跟踪问题_Entity Framework_Entity Framework 4.3 - Fatal编程技术网

Entity framework EF 4.3中的持续变更-变更跟踪问题

Entity framework EF 4.3中的持续变更-变更跟踪问题,entity-framework,entity-framework-4.3,Entity Framework,Entity Framework 4.3,我有一个ReportConfigurationManager类,它管理针对UserReport实体的CRUD操作。感兴趣的两个操作是“Get”和“SaveUpdate”。在这两种情况下,我都将操作包装在using语句中,以便在查询结束时释放DbContext 现在,这些方法最终将构成WCF服务的一部分,但也可以在服务内部调用它们。我目前的困难是让一组直接调用ReportConfigurationManager的单元测试正常工作 我可以创建一个新的UserReport并保存它(这花了我一段时间来解

我有一个ReportConfigurationManager类,它管理针对UserReport实体的CRUD操作。感兴趣的两个操作是“Get”和“SaveUpdate”。在这两种情况下,我都将操作包装在using语句中,以便在查询结束时释放DbContext

现在,这些方法最终将构成WCF服务的一部分,但也可以在服务内部调用它们。我目前的困难是让一组直接调用ReportConfigurationManager的单元测试正常工作

我可以创建一个新的UserReport并保存它(这花了我一段时间来解决,因为该实体有几个嵌套对象,这些对象已经存在于数据库中-在调用UserReport上的Add之前,我需要依次将它们“附加”到上下文中,以使其正确保存

我现在的问题是更新

尽管有

    context.Configuration.ProxyCreationEnabled = false;
    context.Configuration.AutoDetectChangesEnabled = false;
在所有使用ReportConfigurationManager的方法上,当我附加UserReport时,它失败了,出现了经典的“ObjectStateManager中已经存在具有相同键的对象”(我认为禁用更改跟踪就是为了处理这个问题?)

所以现在我转而使用我发现的以下代码

我担心的是,我的代码似乎很费劲——我需要先获得旧对象的副本,然后才能保存更新后的副本?我也不相信我的保存新逻辑

那么这种方法是正确的,还是有更好的方法来写上面的内容呢

其他正在进行的工作的进一步详情:

因为我将通过WCF发送对象图。我已经实现了即时加载:

    public static DbQuery<ReportTemplate> IncludeAll(this DbQuery<ReportTemplate> self)
    {
        return self
            .Include("ReportColumnGroups.ReportColumns.ReportColumnType")
            .Include("ReportColumnGroups.ReportColumnType")
            .Include("ReportSortOptions.ReportSortColumns.ReportColumn.ReportColumnType")
            .Include("ReportSortOptions.ReportSortColumns.ReportSortType");
    }

    public static DbQuery<UserReport> IncludeAll(this DbQuery<UserReport> self)
    {
        return self
            .Include("ReportTemplate")
            .Include("ReportTopType")
            .Include("ReportWindow")
            .Include("ReportSortOption.ReportSortColumns.ReportColumn.ReportColumnType")
            .Include("ReportSortOption.ReportSortColumns.ReportSortType")
            .Include("ReportColumnGroups.ReportColumns.ReportColumnType")
            .Include("ReportColumnGroups.ReportColumnType");

    }


    public static DbQuery<ReportSortOption> IncludeAll(this DbQuery<ReportSortOption> self)
    {
        return self
            .Include("ReportSortColumns.ReportColumn.ReportColumnType")
            .Include("ReportSortColumns.ReportSortType");
    }

    public static DbQuery<ReportColumnGroup> IncludeAll(this DbQuery<ReportColumnGroup> self)
    {
        return self
            .Include("ReportColumn.ReportColumnType")
            .Include("ReportColumnType");
    }

    public static DbQuery<ReportColumn> IncludeAll(this DbQuery<ReportColumn> self)
    {
        return self
            .Include("ReportColumnType");
    }

    public static DbQuery<ReportSortColumn> IncludeAll(this DbQuery<ReportSortColumn> self)
    {
        return self
            .Include("ReportColumn.ReportColumnType")
            .Include("ReportSortType");
    }
我检索用户报告如下:

using (var context = new ReportDataEF())
        {
            context.Configuration.ProxyCreationEnabled = false;
            context.Configuration.AutoDetectChangesEnabled = false;
            reportConfigurationData = new ReportingMetaData()
                                          {
                                              WatchTypes = context.WatchTypes.ToList(),
                                              ReportTemplates = context.ReportTemplates.IncludeAll().ToList(),
                                              ReportTopTypes = context.ReportTopTypes.ToList(),
                                              ReportWindows = context.ReportWindows.ToList(),
                                              ReportSortOptions =
                                                  context.ReportSortOptions.IncludeAll().ToList()
                                          };
        }
public UserReport GetUserReport(int userReportId)
    {
        using (var context = new ReportDataEF())
        {
            context.Configuration.ProxyCreationEnabled = false;
            context.Configuration.AutoDetectChangesEnabled = false;
            var visibleReports =
                context.UserReports.IncludeAll().Where(ur => ur.Id == userReportId).FirstOrDefault();
            return visibleReports;
        }
    }
我关心的测试从数据库中获取一个现有的UserReport,使用静态数据类中的对象更新其ReportTemplate和ReportColumnGroups属性,然后尝试保存更新的UserReport


使用Ladislav答案中的代码,当我尝试附加UserReport时,这会失败,可能是因为我附加到它的一个对象已经存在于数据库中。

是的,还有另一种方法。首先,您应该知道EF不支持部分附加的对象图,所以
附加
添加
附加或添加图形中上下文尚未跟踪的所有实体会产生副作用。这将大大简化插入代码

public UserReport SaveUpdateUserReport(UserReport userReport)
{
    using (var context = new ReportDataEF())
    {
        context.Configuration.ProxyCreationEnabled = false;
        context.Configuration.AutoDetectChangesEnabled = false;

        // Now all entities in the graph are attached in unchanged state
        context.ReportTopTypes.Attach(userReport);

        if (userReport.Id > 0 && 
            context.UserReports.Any(ur => ur.Id == userReport.Id))
        {
            context.Entry(userReport).State = EntityState.Modified;
        }
        else
        {
            context.Entry(userReport).State = EntityState.Added;
        }

        context.SaveChanges();
    }

    return userReport;
}

这相当于您的原始代码。您不再加载用户报告-您只需检查其在数据库中的存在。此代码有很多问题-例如,如果您更改了任何其他相关对象,它将不会持久化到数据库中,因为当前它的状态是
未更改的
。如果您需要更改r,它可能会更加复杂关系。

在对象图中,唯一正在更改的对象是UserReport本身,但它与ReportColumnGroup类存在多对多关系。db中的ReportColumnGroup集合永远不会更改,但与UserReports的关系将更改,因为报表可以在集合中添加或删除ReportColumnGroup。I t尽管我试着做了你放的东西,但它在附加上失败了-我已经经历了很多次迭代,所以我将完全尝试你放在上面的东西,看看它是否有效。是的-失败了,错误是:ObjectStateManager中已经存在一个具有相同键的对象。当我运行行上下文时。UserReports.Attach(userReport);我将在上面添加我的代码的更多详细信息。好的-如果我禁用LazyLoading,并删除我的WangerLoading扩展,那么这一切似乎都起作用了。更正-它主要起作用-我现在的问题是没有填充多对多关系。因此我的UserReport不再检索任何ReportColumnGroups。
public UserReport SaveUpdateUserReport(UserReport userReport)
{
    using (var context = new ReportDataEF())
    {
        context.Configuration.ProxyCreationEnabled = false;
        context.Configuration.AutoDetectChangesEnabled = false;

        // Now all entities in the graph are attached in unchanged state
        context.ReportTopTypes.Attach(userReport);

        if (userReport.Id > 0 && 
            context.UserReports.Any(ur => ur.Id == userReport.Id))
        {
            context.Entry(userReport).State = EntityState.Modified;
        }
        else
        {
            context.Entry(userReport).State = EntityState.Added;
        }

        context.SaveChanges();
    }

    return userReport;
}