public async Task <IActionResult> GetStores([FromQuery] StoreQryDto storeQryDto)
        {
            this._logger.LogInformation("enter 'GetStores' method.");

            if (!this._propertyMappingService.ValidMappingExistsFor <StoreDto, Store>(storeQryDto.OrderFields)) //check if order field exist.
            {
                return(BadRequest());
            }
            if (!this._propertyCheckerService.TypeHasProperties <StoreDto>(storeQryDto.ShapeFields))
            {
                return(BadRequest());
            }

            PagedList <Store> stores = await this._storeDao.Query(storeQryDto);

            var previousPageLink   = stores.HasPrevious ? CreateStoresResourceUri(storeQryDto, ResourceUriType.PreviousPage) : null;
            var nextPageLink       = stores.HasNext ? CreateStoresResourceUri(storeQryDto, ResourceUriType.NextPage) : null;
            var paginationMetadata = new
            {
                totalCount  = stores.TotalCount,
                pageSize    = stores.PageSize,
                currentPage = stores.CurrentPage,
                totalPages  = stores.TotalPages,
            };

            Response.Headers.Add("X-Pagination", JsonSerializer.Serialize(paginationMetadata, new JsonSerializerOptions
            {
                Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
            }));


            var storeDtos = this._mapper.Map <IEnumerable <StoreDto> >(stores);
            //404 NotFound

            //数据塑形
            var shapedData = storeDtos.ShapData <StoreDto>(storeQryDto.ShapeFields);


            //添加Hateoas支持
            var links = CreateLinksForStore(storeQryDto, stores.HasPrevious, stores.HasNext);

            var shapedStoresWithLinks = shapedData.Select(c =>
            {
                var storeDict = c as IDictionary <string, object>;
                if (storeDict.ContainsKey("Id"))
                {
                    var storeLinks = CreateLinksForStore((int)storeDict["Id"], null);
                    storeDict.Add("links", storeLinks);
                }
                return(storeDict);
            });
            var linkedCollectionResource = new
            {
                value = shapedStoresWithLinks,
                links
            };

            return(Ok(linkedCollectionResource));
        }
        private IEnumerable <LinkDto> CreateLinksForStore(StoreQryDto parameters, bool hasPrevious, bool hasNext)
        {
            var links = new List <LinkDto>();

            links.Add(new LinkDto(CreateStoresResourceUri(parameters, ResourceUriType.CurrentPage), "self", "GET"));
            if (hasPrevious)
            {
                links.Add(new LinkDto(CreateStoresResourceUri(parameters, ResourceUriType.PreviousPage), "get_previous_page", "GET"));
            }
            if (hasNext)
            {
                links.Add(new LinkDto(CreateStoresResourceUri(parameters, ResourceUriType.NextPage), "get_next_page", "GET"));
            }
            return(links);
        }
        /// <summary>
        /// 创建翻页的url
        /// </summary>
        /// <param name="parameters"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        private string CreateStoresResourceUri(StoreQryDto parameters, ResourceUriType type)
        {
            switch (type)
            {
            case ResourceUriType.PreviousPage:
                return(Url.Link(nameof(GetStores), new
                {
                    fields = parameters.ShapeFields,
                    pageNumber = parameters.PageNumber - 1,
                    pageSize = parameters.PageSize,
                    nameQry = parameters.NameQry,
                    addressQry = parameters.AddressQry,
                    orderBy = parameters.OrderFields
                }));

            case ResourceUriType.NextPage:
                return(Url.Link(nameof(GetStores), new
                {
                    fields = parameters.ShapeFields,
                    pageNumber = parameters.PageNumber + 1,
                    pageSize = parameters.PageSize,
                    nameQry = parameters.NameQry,
                    addressQry = parameters.AddressQry,
                    orderBy = parameters.OrderFields
                }));

            default:
                return(Url.Link(nameof(GetStores), new
                {
                    fields = parameters.ShapeFields,
                    pageNumber = parameters.PageNumber,
                    pageSize = parameters.PageSize,
                    nameQry = parameters.NameQry,
                    addressQry = parameters.AddressQry,
                    orderBy = parameters.OrderFields
                }));
            }
        }
        public async Task <PagedList <Store> > Query(StoreQryDto queryObject)
        {
            IQueryable <Store> stores = null;

            if (queryObject != null)
            {
                stores = this._context.Stores.Where(s => s.Name.Contains(queryObject.NameQry) && s.Address.Contains(queryObject.AddressQry));
            }
            else
            {
                stores = this._context.Stores;
            }
            var totalData = await stores.CountAsync();

            var mappingDictionary = this._propertyMappingService.GetPropertyMapping <StoreDto, Store>();

            stores = stores.ApplySort(queryObject.OrderFields, mappingDictionary);

            var results = await stores.Skip(queryObject.Skip).Take(queryObject.PageSize).ToListAsync();

            PagedList <Store> queryList = new PagedList <Store>(results, totalData, queryObject.PageNumber, queryObject.PageSize);

            return(queryList);
        }
        public async void DoCurdOperation()
        {
            var storeDao = Provider.GetService <IStoreDao>();
            var mapper   = Provider.GetService <IMapper>();

            #region test add
            var store1 = new Store
            {
                Name    = "Count down",
                Address = "Mt Eden"
            };

            var store2 = new Store
            {
                Name    = "New world",
                Address = "Mt Albert"
            };

            var store3 = new Store
            {
                Name    = "Parking save",
                Address = "City center"
            };

            bool result = await storeDao.Add(store1);

            Assert.True(result);

            result = await storeDao.Add(store2);

            Assert.True(result);

            result = await storeDao.Add(store3);

            Assert.True(result);
            #endregion

            #region update
            store2.Name = "Count down";

            result = await storeDao.Update(store2);

            Assert.True(result);
            #endregion

            #region query
            IEnumerable <Store> stores = await storeDao.QueryAll();

            Assert.NotNull(stores);
            Assert.Equal(3, stores.Count());
            var storeFirst = stores.First();
            var storeLast  = stores.Last();
            Assert.IsType <Store>(storeFirst);
            Assert.IsType <Store>(storeLast);
            Assert.True(storeFirst.Id < storeLast.Id);


            var queryDto = new StoreQryDto
            {
                NameQry     = "down",
                OrderFields = "id desc",
                ShapeFields = "Id"
            };

            PagedList <Store> queryResult = await storeDao.Query(queryDto);

            Assert.NotNull(queryResult);
            Assert.Equal(2, queryResult.TotalCount);
            var storeF = queryResult[0];
            var storeS = queryResult[1];
            Assert.True(storeS.Id < storeF.Id);
            Assert.Equal("Count down", storeS.Name);
            Assert.Equal("Mt Eden", storeS.Address);

            queryDto.PageSize    = 1;
            queryDto.PageNumber  = 2;
            queryDto.OrderFields = "id";

            Assert.Equal(1, queryDto.Skip);

            queryResult = await storeDao.Query(queryDto);

            Assert.NotNull(queryResult);
            Assert.Equal(2, queryResult.TotalCount);
            Assert.Equal(1, queryResult.Count);
            var store = queryResult[0];
            Assert.Equal("Count down", store.Name);
            Assert.Equal("Mt Albert", store.Address);

            #endregion

            #region Shaped

            var storeDtos  = mapper.Map <IEnumerable <StoreDto> >(queryResult);
            var shapedData = storeDtos.ShapData <StoreDto>(queryDto.ShapeFields);
            foreach (var obj in shapedData)
            {
                var storeDict = obj as IDictionary <string, object>;
                Assert.NotNull(storeDict);
                Assert.True(storeDict.ContainsKey("Id"));
                Assert.False(storeDict.ContainsKey("Name"));
                Assert.False(storeDict.ContainsKey("Address"));
            }
            #endregion

            /*
             #region delete
             * result = await storeDao.Delete(store1.Id);
             * Assert.True(result);
             * queryDto.NameQry = "Eden";
             * queryResult = await storeDao.Query(queryDto);
             * Assert.NotNull(queryResult);
             * Assert.Equal(0, queryResult.TotalCount);
             * result = await storeDao.Delete(store2.Id);
             * Assert.True(result);
             * result = await storeDao.Delete(store3.Id);
             * Assert.True(result);
             #endregion
             */
        }