как сериализовать сущности, которые имеют отношение один ко многим и разбивают на страницы в структуре сущностей? - PullRequest
0 голосов
/ 22 апреля 2019

У меня есть две модели для двух таблиц, имеющие отношение внешнего ключа.Мне нужно получить запись из обеих таблиц в одном запросе.

Структура модели следующая: -

  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; }
    }
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": "abc@mail.com",
        "userRole": "HR",
        "id": nbh546652n45
 }]

Но ответ будет следующим: -

[{
        "tblCountries": [],
        "EmployeeId": 350,
        "Name": "ABC",
        "userName": "abc@mail.com",
        "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;

По-прежнему появляется та же ошибка.

Ответы [ 2 ]

1 голос
/ 22 апреля 2019

Спроектируйте модель вашего домена во что-то еще, прежде чем возвращать ее из вашего API. Это лучше контролирует формат данных ответа, и, если свойство добавляется (например, ssn), оно случайно не раскрывается. Это также имеет дополнительное преимущество исправления ваших циклических ссылок.

return items.Select(i => new { 
    i.Name,
    i.Username,
    ...
    Countries = i.Countries.Select(c => new {
            c.CountryId,
            c.CountryName,
            ...
        }
};
0 голосов
/ 22 апреля 2019

Вам необходимо установить отношения между employeeRecord и странами. Попробуйте с этим:

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

И когда вы делаете запрос, вам нужно указать текст: Приложение / Json

...