如何序列化实体框架中具有一对多关系和分页的实体?

问题描述 投票:0回答:2

我有一个两个模型,两个表有外键关系。我必须在单个请求中从两个表中获取记录。

模型结构如下: -

  1. EmployeeRecord.cs
public partial class EmployeeRecord
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public tblEmployeeRecord()
        {
            this.countries = new HashSet<tblCountry>();
        }

        public int EmployeeId { get; set; }
        public string Name { get; set; }
        public string userName { get; set; }
        public string userRole { get; set; }
        public string id { get; set; }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<Country> countries { get; set; }

    }

2.Country.cs

 public partial class Country
    {
        public int CountryId { get; set; }
        public int EmployeeId { get; set; }
        public string CountryName { get; set; }

       public virtual EmployeeRecord employeeRecord { get; set; }
    }
  1. EmployeeController.cs
 public class EmployeeRecordsController : ApiController
    {
        private EstorageEntitiesforCombineView db = new EstorageEntitiesforCombineView();

        // GET: api/EmployeeRecords
        public IEnumerable<EmployeeRecord> GetEmployeeRecords([FromUri]PagingParameterModel pagingparametermodel)
        {
             var source= db.EmployeeRecords.OrderBy(a => a.EmployeeId);

            // Get's No of Rows Count 
             if (pagingparametermodel.userRole == "HR")
            {
                 source= (from a in db.EmployeeRecords
                        where a.userRole == "HR"
                        select a).OrderBy(a => a.EmployeeId);
            }
            else if(pagingparametermodel.userRole == "eStorage Admin")
            {
                source = (from a in db.EmployeeRecords
                          where a.userRole == "eStorage Admin"
                          select a).OrderBy(a => a.EmployeeId);

            } else if(pagingparametermodel.userRole == "SharedService")
            {
                source = (from a in db.EmployeeRecords
                          where a.userRole == "SharedService"
                          select a).OrderBy(a => a.EmployeeId);

            }
             if(pagingparametermodel.toSearch == 1 && pagingparametermodel.userRole == "ALL")
            {
                source = (from b in db.EmployeeRecords
                          where b.Name.StartsWith(pagingparametermodel.name) 
                          select b).OrderBy(a => a.EmployeeId);

            }else if (pagingparametermodel.toSearch==1) {
                source= (from b in db.EmployeeRecords
                        where b.Name.StartsWith(pagingparametermodel.name) && b.userRole==pagingparametermodel.userRole
                        select b).OrderBy(a => a.EmployeeId);

            }
            int count = source.Count();

            // Parameter is passed from Query string if it is null then it default Value will be pageNumber:1  
            int CurrentPage = pagingparametermodel.pageNumber;

            // Parameter is passed from Query string if it is null then it default Value will be pageSize:20  
            int PageSize = pagingparametermodel.pageSize;

            // Display TotalCount to Records to User  
            int TotalCount = count;

            // Calculating Totalpage by Dividing (No of Records / Pagesize)  
            int TotalPages = (int)Math.Ceiling(count / (double)PageSize);

            // Returns List of Customer after applying Paging   
            var items = source.Skip((CurrentPage - 1) * PageSize).Take(PageSize).ToList();

            // if CurrentPage is greater than 1 means it has previousPage  
            var previousPage = CurrentPage > 1 ? "Yes" : "No";

            // if TotalPages is greater than CurrentPage means it has nextPage  
            var nextPage = CurrentPage < TotalPages ? "Yes" : "No";

            // Object which we are going to send in header   
            var paginationMetadata = new
            {
                totalCount = TotalCount,
                pageSize = PageSize,
                currentPage = CurrentPage,
                totalPages = TotalPages,
                previousPage,
                nextPage
            };

            // Setting Header  
            System.Web.HttpContext.Current.Response.Headers.Add("Paging-Headers", Newtonsoft.Json.JsonConvert.SerializeObject(paginationMetadata));
            // Returing List of Customers Collections  
            return items;

        }
}

我希望回复如下: -

[{
        "tblCountries": [
            {
                "CountryId": 265,
                "EmployeeId": 350,
                "CountryName": "INWEST"
            }
        ],
        "EmployeeId": 350,
        "Name": "ABC",
        "userName": "[email protected]",
        "userRole": "HR",
        "id": nbh546652n45
 }]

但回应如下: -

[{
        "tblCountries": [],
        "EmployeeId": 350,
        "Name": "ABC",
        "userName": "[email protected]",
        "userRole": "HR",
        "id": nbh546652n45
 }]

我也试过,Include(a => a.countries)如下: -

source= (from a in db.EmployeeRecords
            where a.userRole == "HR"
           select a).Include(a => a.countries).OrderBy(a => a.EmployeeId);

但我得到以下错误: -

<ExceptionMessage>
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace/>
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Object graph for type 'System.Collections.Generic.HashSet`1[[eStorageApi.Models.tblCountry, eStorageApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' contains cycles and cannot be serialized if reference tracking is disabled.
</ExceptionMessage>
<ExceptionType>
System.Runtime.Serialization.SerializationException
</ExceptionType>

尝试将这些LOC包含在webApiConfig.cs中: -

config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling= Newtonsoft.Json.ReferenceLoopHandling.Ignore;
config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.None;

仍然得到同样的错误。

entity-framework asp.net-web-api configuration foreign-keys lazy-loading
2个回答
1
投票

在从api返回之前,将您的域模型投射到其他内容中。这样可以更好地控制响应数据格式,如果添加了属性(例如ssn),则不会无意中暴露它。这也有固定您的周期性参考的额外好处。

return items.Select(i => new { 
    i.Name,
    i.Username,
    ...
    Countries = i.Countries.Select(c => new {
            c.CountryId,
            c.CountryName,
            ...
        }
};

0
投票

您需要在employeeRecord和国家/地区之间建立关系。试试这个:

 source= db.EmployeeRecords.Include(e => e.countries).Select(c => c.employeeRecord)
           .Where(a => a.userRole == "HR");

当您执行请求时,您需要指定文本:Application / Json

© www.soinside.com 2019 - 2024. All rights reserved.