【问题标题】:Formatting Serialized JSON With Code-First Entity Framework使用 Code-First Entity Framework 格式化序列化 JSON
【发布时间】:2013-06-28 08:25:21
【问题描述】:

我正在使用Web-API GET 为报告返回 JSON。

GET 方法返回一个简单的db.Reports.ToList();

这是我检索到的数据的转储

{
        "Project": {
            "Location": {
                "LocationId": 7,
                "Description": "New York"
            },
            "Department": {
                "DepartmentId": 7,
                "Description": "Engineering"
            },
            "ProjectId": 7,
            "Description": "Project_3",
            "LocationId": 7,
            "DepartmentId": 7
        },
        "Person": {
            "Email": "email@gmail.com",
            "FirstName": "John",
            "LastName": "Doe",
            "IsActive": true
        },
        "StatusCode": {
            "StatusId": 8,
            "Description": "Accepted"
        },
        "ReportId": "d4cddb3f-ea6a-4b0a-9820-19bd8ee43b3a",
        "Description": "Report 3",
        "RoundTrip": 45.88,
        "IsBillable": true,
        "StartDate": "2013-06-27T00:00:00",
        "EndDate": "2013-06-27T14:36:32.467",
        "TimeUpdated": "AAAAAAAAJxM="
    }, ... 
}

这是相关的报告声明:

public class Report
{
    public Guid ReportId { get; set; }
    public string Description { get; set; }
    public double RoundTrip { get; set; }
    public bool IsBillable { get; set; }

    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }

    public virtual Project Project { get; set; }

    public byte[] TimeUpdated { get; set; }

    public virtual Person Person { get; set; }

    public virtual StatusCode StatusCode { get; set; }
}

在这种情况下,我真的很想在 Report 类中包含各种对象的 ID。例如,我真的很想看看:

    "Project": 7,
    "Location": 7,
    "Department": 7,
    "Person": "email@gmail.com",
    "StatusCode": 8,
    "ReportId": "d4cddb3f-ea6a-4b0a-9820-19bd8ee43b3a",
    "Description": "Report 3",
    "RoundTrip": 45.88,
    "IsBillable": true,
    "StartDate": "2013-06-27T00:00:00",
    "EndDate": "2013-06-27T14:36:32.467",
    "TimeUpdated": "AAAAAAAAJxM="
  1. 是否有一种相对简单的方法来执行此操作,或者进一步解析我已经看到的结果是否更符合我的利益?
  2. 为什么默认情况下 EF 在 JSON 中创建这些对象而不仅仅是外键?

【问题讨论】:

  • 我会使用 LINQ 从旧的 json 中投影新的 json。那或者创建另一个类并编写一个自定义转换器。我会根据您在整个代码库中使用结果的程度来做出选择。没有简单的方法可以像那样更改 json(当然除了更改 API)。
  • 是的,谢谢@evanmcdonnal

标签: c# json entity-framework asp.net-web-api ef-code-first


【解决方案1】:

您无需专门创建新类即可。在您的ApiController 中,如果您使用类型化的返回类型(支持HttpResponseMessage),请将List 类型更改为IEnumerable<object> 并返回:

return db.Reports.Select(r => new {
    Project = r.ProjectId;
    Location = r.Location.LocationId;
    Department = r.Department.DepartmentId;
    Person = r.Person.Email;
    StatusCode = r.StatusCode.StatusId;
    Description: r.Description
    RoundTrip: r.RoundTrip
    IsBillable: r.IsBillable,
    StartDate: r.StartDate,
    EndDate: r.EndDate
    TimeUpdated: r.TimeUpdated
});

// Or if you're using HttpResponseMessage
return Request.CreateResponse(HttpStatusCode.Ok, 
    db.Reports.Select(r => new {
        Project = r.ProjectId;
        Location = r.Location.LocationId;
        Department = r.Department.DepartmentId;
        Person = r.Person.Email;
        StatusCode = r.StatusCode.StatusId;
        Description: r.Description
        RoundTrip: r.RoundTrip
        IsBillable: r.IsBillable,
        StartDate: r.StartDate,
        EndDate: r.EndDate
        TimeUpdated: r.TimeUpdated
    }));

默认的 Json 序列化器(Newtonsoft 的 Json.Net)足够智能,可以序列化匿名对象。上面代码中唯一未知的是TimeUpdated 成员的行为,因为它是一个字节数组。您可能需要调整分配。

【讨论】:

  • 嗨,西蒙,感谢您的建议。我没有想过只返回通用对象而不是 Report 对象,所以我试图强制进行不必要的强制转换。即使卡梅伦的回答也是正确的,我也会接受这个答案,因为这种方式正是我所追求的,而不会产生过多的标记。
  • +1 这是一个很好的解决方案。我也没有想到这一点。以后在我的 API 中返回 JSON 时,我会牢记这一点。
  • 这是在创建一个新类,它只是匿名的。在编译时,C# 编译器创建一个类定义,就像其他任何名称一样。如果您要使用返回的对象,则使用广泛使用明确定义类肯定更好。
  • 没错。只是语法糖,是的,如果它在其他地方使用,请定义 de class。但它应该使用对象初始化器语法构造,以便 EF 仅加载所需的属性
【解决方案2】:

我建议制作一个模型来显示您希望显示的 JSON。这将是最简单的选择。

这样的事情应该可以工作:

public class ReportSimple
{
    public Guid ReportId { get; set; }
    public int Project { get; set; }
    public int Location { get; set; } 
    public int Department { get; set; }
    public string Person { get; set; }
    public int StatusCode { get; set; }
    public string Description { get; set; }
    public double RoundTrip { get; set; }
    public bool IsBillable { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
    public byte[] TimeUpdated { get; set; }

    public ReportSimple(Project project, Person person, StatusCode statusCode)
    {
        Project = project.ProjectId;
        Location = project.Location.LocationId;
        Department = project.Department.DepartmentId;
        Person = person.Email;
        StatusCode = statusCode.StatusId;
    }
}

【讨论】:

  • 你能举一个与上述相关的简单例子吗?
  • 应该是评论,而不是答案。
  • @evanmcdonnal 你是对的。我正在编写一些示例类。
  • 感谢 Cameron,我为您 +1 提供了一个可行的解决方案,尽管我认为 Simon 的回答更符合我的目的,因为它阻止了我创建所有这些冗余标记。
  • 要在 Cameron 的答案中再添加一件事,问题是如果你这样做:db.Reports.Select(r =­> new ReportSimple(r.Project, r.Person, r.StatusCode)).ToList() Entity Framework 将在将结果传递给 ReportSimple 构造函数之前完全实现结果,因为它无法检查构造函数的代码和有效地决定他是否需要财产。它本质上将从数据库中获取所有内容。更糟糕的是,project.Department.DepartmentId 将为每个 ReportSimple 生成一个新查询,除非在启用延迟加载的情况下明确包含它
猜你喜欢
  • 2017-05-31
  • 2014-03-07
  • 2016-08-22
  • 2021-02-03
  • 1970-01-01
  • 1970-01-01
  • 2011-08-05
  • 2023-04-02
  • 1970-01-01
相关资源
最近更新 更多