В Microsoft.AspNetCore. Mvc: предотвращение использования _context кэшированных результатов при инициализации модели. - PullRequest
0 голосов
/ 21 апреля 2020

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

Другая функция в этой таблице - это столбец, ссылающийся на ветвь.

Ветка имеет разрешение на просмотр всех записей, связанных с этой записью (родитель или потомки, но не в боковом направлении).

Для этого я получу все сущности, связанные с веткой, а затем рекурсивно получу их дети, пока у меня нет списка сущностей, у которых нет детей. В этот момент я надеялся использовать метод DBContext «OnModelCreating» для извлечения последовательной цепочки объектов, пока она не достигнет верхнего уровня.

Это работает частично. Все работает, пока я не доберусь до метода OnModelCreating, где он извлекает родительские объекты, пока не доберется до родительского объекта с BranchId.

Я предполагаю, что он использует кэшированный результат из строки marketsUnknownChildren = await _context.Markets.Where(x => x.BranchID.Equals(brancheID)).ToListAsync();. Поскольку для родительского объекта «BranchID» установлено значение «null», метод «OnModelCreating» не находит никаких объектов и оставляет параметр «ParentMarket» в качестве «null».

Я проверил это, назначив различные уровни иерархии к ветви. Каждый раз он возвращает все записи, которые не имеют дочерних элементов и цепочки родительских объектов до уровня, который содержит ветвь.

Как мне:

перезагружать объекты с parentIds, но без parentObject

или предотвращать применение предложения where к родительскому объекту

или нет кэшировать результаты первого запроса?

Спасибо.

Market

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;

namespace TenantToolVmApi.Models
{
    [Table("Markets")]
    public class Market
    {
        [Key]
        public int ID { get; set; }

        [Column("Branch ID")]
        public int? BranchID { get; set; }

        [Column("ParentId")]
        public int? ParentId { get; set; }

        [ForeignKey("ParentId")]
        public virtual Market? ParentMarket { get; set; }

        [Column("Canada_Plus_MarketsID")]
        public int Canada_Plus_MarketsID {get; set;}

        [Column ("Name")]
        public string Name { get; set; }
    }
}

MarketContext

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;

namespace TenantToolVmApi.Models
{
    public class MarketContext : DbContext
    {
        public MarketContext(DbContextOptions<MarketContext> options)
            : base(options)
        {
        }

        public DbSet<Market> Markets { get; set; }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Market>()
                .HasOne(u => u.ParentMarket);
        }
    }
}

MarketCotroller

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TenantToolVmApi.Models;

namespace TenantToolVmApi.Controllers
{
    [Authorize]
    [ApiController]
    [Route("[controller]")]
    public class MarketsController : ControllerBase
    {
        private readonly MarketContext _context;

        public MarketsController(MarketContext context)
        {
            _context = context;
        }

        // GET: api/Markets
        [HttpGet]
        public async Task<ActionResult<IEnumerable<Market>>> GetMarketsItems()
        {
            string userName = HttpContext.User.Identity.Name;
            PermissionController permissionController = new PermissionController(userName);
            if (permissionController.HasNationalScope())
                return await _context.Markets.ToListAsync();
            else
            {
                int brancheID = permissionController.GetAccessibleBranches();

                IEnumerable<Market> marketsHasNoChildren = new List<Market>();
                List<int> addedIds = new List<int>();
                IEnumerable<Market> marketsUnknownChildren;
                IEnumerable<Market> marketsToCheckOnNextPass;
                IEnumerable<Market> result;


                marketsUnknownChildren = await _context.Markets.Where(x => x.BranchID.Equals(brancheID)).ToListAsync();

                while (marketsUnknownChildren.Count() > 0)
                {
                    marketsToCheckOnNextPass = new List<Market>();
                    foreach (Market market in marketsUnknownChildren)
                    {
                        result = await _context.Markets.Where(x => x.ParentId.Equals(market.ID)).ToListAsync();
                        if (result.Count() > 0)
                            marketsToCheckOnNextPass = marketsToCheckOnNextPass.Concat(result);
                        else if (!addedIds.Contains(market.ID))
                        {
                            marketsHasNoChildren = marketsHasNoChildren.Concat(new List<Market> { market });
                            addedIds.Add(market.ID);
                        }
                    }
                    marketsUnknownChildren = marketsToCheckOnNextPass;
                }

                ActionResult<IEnumerable<Market>> returnActionResults = marketsHasNoChildren.ToList();
                return returnActionResults;
            }
        }

        private bool MarketsExists(int id)
        {
            return _context.Markets.Any(e => e.ID == id);
        }
    }
}

1 Ответ

0 голосов
/ 22 апреля 2020

Похоже, что для вашего дизайна модели в Market существует отношение "один к одному" с собственной ссылкой. И оператор ? используется после ненулевого простого типа, а не сложного типа. См. Следующий код:

[Table("Markets")]
public class Market
{
    [Key]
    public int ID { get; set; }

    [Column("Branch ID")]
    public int? BranchID { get; set; }

    [Column("ParentId")]
    public int? ParentId { get; set; }

    [ForeignKey("ParentId")]
    public virtual Market ParentMarket { get; set; }

    [Column("Canada_Plus_MarketsID")]
    public int Canada_Plus_MarketsID { get; set; }

    [Column("Name")]
    public string Name { get; set; }
}

modelBuilder.Entity<Market>()
            .HasOne(u => u.ParentMarket)
            .WithOne()
            .HasForeignKey<Market>(u => u.ParentId)
            .IsRequired(false);

И затем вы можете использовать метод Include() для загрузки связанных данных

await _context.Markets.Include(m=>m.ParentMarket).Where(x => x.BranchID.Equals(brancheID)).ToListAsync();

Результат

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...