首页 > 解决方案 > 我的一个实体不是代理

问题描述

我收到的错误-

mscorlib.dll 中出现“System.ArgumentException”类型的未处理异常

附加信息:值“PHSRP_Dashboard.WorkSessionBreak”不是“System.Data.Entity.DynamicProxies.WorkSessionBreak_06908<..many characters..>6E3E”类型,不能在此通用集合中使用。

仅在将新的 WorkSessionBreak 记录添加到数据库时发生。它不会发生在仅被修改的记录中,也不会在重新启动程序并且重新访问(不是这样)新记录时再次发生。

private void Edit_WorkSessionBreak_FormClosed(object sender, FormClosedEventArgs e)
{
    if (SelectedWorkSessionID >= 0)
    {
        var BreakSet = editEmployee.EmployeeWorkSessions
                                   .SelectMany(ws => ws.WorkSessionBreaks)
                                   .Where(b => b.DELETED != true && b.EmployeeWorkSessionID == SelectedWorkSessionID);

        if (BreakSet.Any())
        {
            var BreakSetSorted = BreakSet.OrderBy(b => b.OutTime);
            this.bs_WorkSessionBreaks_Display.DataSource = BreakSetSorted;        //  Blows-up on New record added.
        }
        else
        {
            this.bs_WorkSessionBreaks_Display.DataSource = new BindingList<WorkSessionBreak>();
        }
    }
    else
    {
        this.bs_WorkSessionBreaks_Display.DataSource = new BindingList<WorkSessionBreak>();
    }

    if (bs_WorkSessionBreaks_Display.Count > 0)
    {
        if (syncToViewBreak(((WorkSessionBreak)bs_WorkSessionBreaks_Display.Current).WorkSessionBreakID))
        {
            SelectedWorkSessionBreakID = ((WorkSessionBreak)bs_WorkSessionBreaks_Display.Current).WorkSessionBreakID;
        }
    }

    bs_WorkSessionBreaks_Display.ResetBindings(false); 
}

我们返回的 Dialog 表单工作正常。更改/添加已正确放置在数据库中,但与此 Parent 表单关联的 BindingSources 不会自动重新排序。

检查调试器中的变量内容表明 LINQ 返回的 Enumerable 中的新记录是 WorkSessionBreak 而其他预先存在的项目是 WorkSessionBreak Proxies

调试器视图 1

排序工作但也返回类型和代理的混合:

调试器视图 2

下一条指令崩溃,因为一个项目与其他项目的类型不同(即代理)。

调试器视图 3

我不知道该怎么办或为什么会发生。此算法用于相同形式的其他部分,不会发生此错误。

标签: c#entity-frameworkentity-framework-6

解决方案


您面临的是所谓的延迟执行。基本上,代码试图将项目添加到数据库查询中。

这里:

var BreakSet = editEmployee.EmployeeWorkSessions
    .SelectMany(ws => ws.WorkSessionBreaks)
    .Where(b => b.DELETED != true 
             && b.EmployeeWorkSessionID == SelectedWorkSessionID);

BreakSet是一个IQueryable<WorkSessionBreak>。每当您看到IQueryable<SomeClass>时,请记住它代表一个查询,并且(通常)不是您在内存中的数据。

var BreakSet = editEmployee.EmployeeWorkSessions
   .SelectMany(ws => ws.WorkSessionBreaks)
   .Where(b => b.DELETED != true 
            && b.EmployeeWorkSessionID == SelectedWorkSessionID)
   .OrderBy(b => b.OutTime)
   .ToList();

if (BreakSet.Any())
{
    this.bs_WorkSessionBreaks_Display.DataSource = BreakSet;
}

有了这个,你现在有一个单一的数据库调用。该OrderBy子句不会影响COUNT查询的结果,因此您可以将其作为初始查询的一部分。请注意,最后的ToList()调用是执行查询的原因,因此结果被具体化。


推荐阅读