我对Action回复我的错误感到困惑。我的经理有一个代码:
public class AddressesManager
{
private SiteDBEntities entityContext;
public Addresses GetAddress(short id)
{
entityContext = new SiteDBEntities();
var addressList = entityContext.Addresses.Where(a => a.Id == id).FirstOrDefault();
entityContext.Dispose();
return addressList;
}
}
调用此函数的动作:
[HttpPost]
public ActionResult LoadAddress(short id)
{
AddressesManager mngr = new AddressesManager();
Addresses address = mngr.GetAddress(id);
return new JsonResult() { Data = address };
}
和jquery代码一起调用thit action:
$.post("/Cart/LoadAddress", { id: id })
.success(function (data) {
console.log(data);
})
.fail(function (e) { console.log(e) });
操作正在运行,但此代码总是出现500错误:
ObjectContext实例已被处理,无法再用于需要连接的操作。
据我所知,问题出在 entityContext 上,但为什么会这样呢?我已经从DB执行了数据,我不再需要连接......
修改
这是我的地址模型。它由EF自动生成:
public partial class Addresses
{
public int Id { get; set; }
public string Title { get; set; }
public string State { get; set; }
public string Country { get; set; }
public string Warehouse { get; set; }
public string FirstName { get; set; }
public string SecondName { get; set; }
public string Phone { get; set; }
public short DeliveryType { get; set; }
public System.Guid UserId { get; set; }
public virtual DeliveryType DeliveryType1 { get; set; }
public virtual Users Users { get; set; }
}
答案 0 :(得分:1)
发生错误是因为您的Address
类有2个虚拟属性:DeliveryType1
和Users
。
将address
转换为JSON时,它会尝试访问这些虚拟属性。但是,那时你的上下文已经被处理掉了。
要避免此问题,您不应直接返回EF自动生成的类。而是创建一个DTO对象(数据传输对象),其中只包含您需要的一些字段,将其与EF对象一起映射,然后将其返回。例如:
public class AddressesDTO
{
public int Id { get; set; }
public string Title { get; set; }
public string State { get; set; }
public string Country { get; set; }
public string Warehouse { get; set; }
public string FirstName { get; set; }
public string SecondName { get; set; }
public string Phone { get; set; }
public short DeliveryType { get; set; }
public System.Guid UserId { get; set; }
}
然后,映射它:
public Addresses GetAddress(short id)
{
entityContext = new SiteDBEntities();
var addressList = entityContext.Addresses.Where(a => a.Id == id).FirstOrDefault();
// Create DTO object
AddressesDTO address = new AddressesDTO();
// Map it
address.Id = addressList.Id;
address.Title = addressList.Title
// Go on, it's quite long...
entityContext.Dispose();
return address;
}
但是,正如您所看到的,映射过程非常无聊。更好的方法是使用Automapper。
答案 1 :(得分:1)
如果您想使用实体数据模型,我建议您在post中查看我的答案。
现在,我要做的是创建一个DTO,只获取传递给View所需的数据,就像@AnhTriet提出的那样。为了避免每次需要将查询投射到DTO时自己映射每个属性,我建议使用Automapper。如果您决定使用它,请告诉我您的解决方案:
public class AddressesManager
{
public Addresses GetAddress(short id)
{
using(var entityContext = new SiteDBEntities())
{
var address = entityContext.Addresses
.Where(a => a.Id == id)
.ProjectTo<AddressDTO>()
.FirstOrDefault();
return address;
}
}
}
关于ProjectTo扩展方法。
答案 2 :(得分:0)
您的地址类中是否有导航(子)属性?在DbContext被处理之后,我感觉你正试图访问这个子属性,因为默认情况下子属性是延迟加载的。
您可以发布地址模型的代码吗?
答案 3 :(得分:0)
我认为你应该将属性[JsonIgnore]添加到地址类的虚拟属性。
class Addresses
{
public int ID { get; set; }
[JsonIgnore]
public virtual Something Something { get; set; }
}
答案 4 :(得分:0)
在您的情况下,地址应该是延迟加载的。因此,您正在尝试访问已处置的数据,并且实体框架尝试使用已处置的上下文,这会产生异常。
也许您需要将addressList附加到当前上下文以启用延迟加载
var addressList = entityContext.Addresses.Where(a => a.Id == id).FirstOrDefault();
entityContext.Addresses.Attach(addressList);
答案 5 :(得分:0)
当您在MVC中返回json记录时,您需要在控制器中添加AllowGet:
return Json(new { data= address }, JsonRequestBehavior.AllowGet);
有了这个,你应该没事。