实体框架模型到Json结果

时间:2016-05-13 13:44:45

标签: c# asp.net json asp.net-mvc entity-framework

我对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; }
    }

6 个答案:

答案 0 :(得分:1)

发生错误是因为您的Address类有2个虚拟属性:DeliveryType1Users

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);

有了这个,你应该没事。