Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/323.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/15.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
C# 什么';这是EF的基本概念,即I';我失踪了?_C#_Asp.net Mvc_Entity Framework_Entity Framework 5_Code First - Fatal编程技术网

C# 什么';这是EF的基本概念,即I';我失踪了?

C# 什么';这是EF的基本概念,即I';我失踪了?,c#,asp.net-mvc,entity-framework,entity-framework-5,code-first,C#,Asp.net Mvc,Entity Framework,Entity Framework 5,Code First,我肯定我误解了EF5的一些基本原理 在[上一个问题]中,我询问了如何在ASP.NET MVC应用程序中的操作之间传递值,有人建议我可以使用TempData作为传递数据的机制(在我的例子中,我选择了在EF中表示我的数据模型的POCO) 我在MVC中的控制器不知道EF中有任何持久性机制。它们利用我称之为“管理器”的服务层在我的POCO上执行常见任务,并将它们读取/持久化到底层数据存储 我正在编写一个工作流,允许我的网站的“员工”取消“离职请求”。在控制器和操作方面,有一个HttpGet操作“Canc

我肯定我误解了EF5的一些基本原理

在[上一个问题]中,我询问了如何在ASP.NET MVC应用程序中的操作之间传递值,有人建议我可以使用TempData作为传递数据的机制(在我的例子中,我选择了在EF中表示我的数据模型的POCO)

我在MVC中的控制器不知道EF中有任何持久性机制。它们利用我称之为“管理器”的服务层在我的POCO上执行常见任务,并将它们读取/持久化到底层数据存储

我正在编写一个工作流,允许我的网站的“员工”取消“离职请求”。在控制器和操作方面,有一个HttpGet操作“CancelLeaveRequest”,它获取有问题的LeaveRequest的ID,通过服务层检索LeaveRequest,并显示一些详细信息、警告和确认按钮。在控制器返回相关视图之前,它将LeaveRequest实体提交到TempData中,以便在下一步中提取

确认按钮导致HttpPost“LeaveRequest”,然后使用来自TempData的LeaveRequest和对服务层的调用对LeaveRequest进行更改,并使用EF将其保存回数据库

在我的代码中,manager类的每个实例都有自己的EF DBContext。MVC中的控制器实例化一个管理器,并在页面生命周期内处理它。因此,使用DBContext的一个实例检索LeaveRequest,并通过另一个实例进行更改和提交

我的理解是,当第一个DBContext超出范围时,实体就会“分离”。因此,当我尝试提交对第二个DBContext的更改时,我必须使用DBContext.LeaveRequests.attach()将实体附加到上下文?还有一个更复杂的问题,我需要使用“Employee”实体来记录哪个员工取消了休假请求

我在服务层中用于取消请假请求的代码如下所示

public void CancelLeaveRequest(int employeeId, LeaveRequest request)
{
  _DBContext.LeaveRequests.Attach(request);
  request.State = LeaveRequestApprovalState.Cancelled;
  request.ResponseDate = DateTime.Now;

  using (var em = new EmployeesManager())
  {
    var employee = em.GetEmployeeById(employeeId);
    request.Responder = employee;
    _DBContext.Entry(request.Responder).State = System.Data.EntityState.Unchanged;
  }

  _CommitDatabaseChanges();
}
您可以看到,我从EmployeesManager中检索了一个雇员实体,并将该雇员指定为休假请求的响应者

在我的测试用例中,请假请求的“响应者”与请假请求的另一个属性“请求者”是同一个雇员。请假请求和提出请求的员工之间的关系是多对一的,请假请求和作出响应的员工之间的关系是多对一的

当我的代码在当前状态下运行时,出现以下错误:

AcceptChanges无法继续,因为对象的键值与ObjectStateManager中的另一个对象冲突。在调用AcceptChanges之前,请确保键值是唯一的

我怀疑这是因为英孚认为它已经知道有关员工的情况。失败的线路是:

_DBContext.Entry(request.Responder).State = System.Data.EntityState.Unchanged;
但是,如果我删除了这一行,并且不想通过告诉EF不要更改我的员工对象来表现得聪明,那么请假请求会像预期的那样被取消,但我的员工会发生一些非常奇怪的事情

首先,提出/响应请求的员工是重复的。然后,任何导航属性(如“经理”,员工和其他员工之间的多对一关系)似乎也会被复制。我可以理解,在Employee上复制Manager属性是因为我正在加载Manager对象图,作为
GetEmployeeById
的一部分,并且我认为我可以理解原始员工正在被复制,因为就LeaveRequest DBContext而言,它只是突然出现(我通过另一个DBContext检索了该员工)。但是,假设这两点是正确的,我不知道如何才能a)防止该员工及其关联的对象图在数据库中重复,以及b)如何确保修改后的LeaveRequest正确持久化(在员工和请假申请中,似乎停止了附加、将状态更改为修改等各种组合)

有人能指出我的错误吗


我的请求实体:

public class LeaveRequest
{
    public LeaveRequest()
    {
        HalfDays = new List<LeaveRequestHalfDay>();
    }

    public int CalculatedHalfDaysConsumed { get; set; }

    public Employee Employee { get; set; }

    public virtual ICollection<LeaveRequestHalfDay> HalfDays { get; set; }

    public int LeaveRequestId { get; set; }

    public DateTime RequestDate { get; set; }

    public int ResponderId { get; set; }
    public virtual Employee Responder { get; set; }

    public DateTime? ResponseDate { get; set; }

    public LeaveRequestApprovalState State { get; set; }

    public LeaveRequestType Type { get; set; }

    public ICollection<LeaveRequest> ChildRequests { get; set; }
    public LeaveRequest ParentRequest { get; set; }
}
公共类请求
{
公众假期申请()
{
半天=新列表();
}
public int CalculatedHalfDaysConsumed{get;set;}
公共雇员雇员{get;set;}
公共虚拟ICollection半天{get;set;}
公共请求ID{get;set;}
公共日期时间请求日期{get;set;}
public int ResponderId{get;set;}
公共虚拟员工响应程序{get;set;}
公共日期时间?响应日期{get;set;}
public LeaveRequestApprovalState状态{get;set;}
public LeaveRequestType类型{get;set;}
公共ICollection子请求{get;set;}
public LeaveRequest ParentRequest{get;set;}
}

“Employee”字段(类型为Employee…)是提交请求的人。“Responder”可能是不同的,但可能是相同的Employee。

您应该将导航属性更改为:

public int ResponderId {get;set;}
public virtual Employee Responder { get; set; }
此标量属性将通过EF自动映射到导航属性。接下来,您可以简单地执行以下操作(并且不需要
未更改的
状态):


另请参阅关于EF中的关系。

我认为您的模型缺少外键。能否显示
LeaveRequest
类?更新的问题。我是否需要LeaveRequest上的ResponderId int字段?我更改了LeaveRequest的实体,但EF希望添加:ALTER TABLE[dbo].[LeaveRequests]add[ResponderId][int]NOT NULL默认值0我还向映射中添加了以下内容:this.HasOptional(x=>x.Responder)。WithMany().Map(x=>x.MapKey(“ResponderID”);将测试并确认,谢谢!再次更新问题。我现在有了一个ResponderID int字段,Responder现在是虚拟的。代码已更改为只附加LeaveRequest,而不是我设置的Employee
var employee = em.GetEmployeeById(employeeId);
request.ResponderId = employee.Id;