Выбор значений TreeView на основе отношений «многие ко многим» в модели бритвенных страниц - PullRequest
0 голосов
/ 26 сентября 2019

У меня есть проект страниц Razor, который пытается заполнить Kendo TreeView (или любой другой TreeView) из базы данных, созданной с помощью модели данных.

Страница, над которой я работаю, содержит приложения, которые используютсяи дерево читает список организаций, ссылающихся на себя, чтобы мы знали, к каким приложениям имеет доступ каждая организация или отдел и т. д.Я работаю над страницей «Изменить» в бритвенном приложении, поэтому ~ Pages \ Apps \ Edit.cshtml и ~ Pages \ Apps \ Edit.cshtml.cs со связанными страницами модели, как показано ниже.Это участвующие модели, игнорируйте RoleApps для этой проблемы:

namespace FliveRetry.Models
{
    public class Org
    {
        public int ID { get; set; }
        public string OrgName { get; set; }
        public int? ParentID { get; set; }
        public bool? HasChildren { get; set; }
    }
}

и

namespace FliveRetry.Models
{
    public class App
    {

        public int ID { get; set; }
        public string AppName { get; set; }
        public string AppDescription { get; set; }
        public int? DisplayOrder { get; set; }
        public bool? Archived { get; set; }
        public DateTime? Saved { get; set; }
        public int? SavedBy { get; set; }


        public ICollection<OrgAppJoin> OrgAppJoins { get; set; }
        public ICollection<RoleAppJoin> RoleAppJoins { get; set; }
    }
}

и модель индекса:

{
    public class AppIndexData
    {       

        public IEnumerable<App> Apps { get; set; }
        public IEnumerable<Role> Roles { get; set; }
        public IEnumerable<Org> Orgs { get; set; }
        public IEnumerable<RoleAppJoin> RoleAppJoins { get; set; }
        public IEnumerable<OrgAppJoin> OrgAppJoins { get; set; }
    }
    public class AssignedAppOrgData
    {
        public int OrgID { get; set; }
        public string Org { get; set; }
        public int? ParentID { get; set; }
        public bool Assigned { get; set; }
        public bool? HasChildren { get; set; }
    }
    public class SelectedAppOrgs
    {
        public int OrgID { get; set; }
    }
    public class SelectedAppOrgNames
    {
        public string OrgName { get; set; }
    }

У меня есть модель страницызаполнить выбранные элементы в списки с именем selectedOrgs или selectedOrgNames, которые я могу использовать в представлении.

 public class AppSelectPageModel : PageModel
    {

        //Load list for Selecting Orgs for Apps
        public List<AssignedAppOrgData> AssignedAppOrgDataList;
        public List<SelectedAppOrgs> selectedOrgs;
        public List<SelectedAppOrgNames> selectedOrgNames;
        public void PopulateAssignedAppOrgData(FliveRetryContext context, App app)
        {
            var allOrgs = context.Org;
            var appOrgs = new HashSet<int>(
                app.OrgAppJoins.Select(c => c.OrgID));
            AssignedAppOrgDataList = new List<AssignedAppOrgData>();
            selectedOrgs = new List<SelectedAppOrgs>();
            selectedOrgNames = new List<SelectedAppOrgNames>();
            foreach (var org in allOrgs)
            {
                AssignedAppOrgDataList.Add(new AssignedAppOrgData
                {
                    OrgID = org.ID,
                    Org = org.OrgName,
                    Assigned = appOrgs.Contains(org.ID)  
                });
                if (appOrgs.Contains(org.ID))
                {
                    selectedOrgs.Add(new SelectedAppOrgs
                    {
                        OrgID = org.ID
                    });
                    selectedOrgNames.Add(new SelectedAppOrgNames
                    {
                        OrgName = org.OrgName
                    });
                }
            }
        }

        public void UpdateAppOrgs(FliveRetryContext context,
            string[] selectedOrgs, App appToUpdate)
        {
            if (selectedOrgs == null)
            {
                appToUpdate.OrgAppJoins = new List<OrgAppJoin>();
                return;
            }
            var selectedOrgsHS = new HashSet<string>(selectedOrgs);
            var appOrgs = new HashSet<int>
                (appToUpdate.OrgAppJoins.Select(c => c.Org.ID));

            foreach (var org in context.Org)
            {
                if (selectedOrgsHS.Contains(org.OrgName.ToString()))
                {
                    if (!appOrgs.Contains(org.ID))
                    {
                    appToUpdate.OrgAppJoins.Add(
                        new OrgAppJoin
                        {
                            AppID = appToUpdate.ID,
                            OrgID = org.ID
                        });
                    }
                }
                else
                {
                    if (appOrgs.Contains(org.ID))
                    {
                        OrgAppJoin orgToRemove
                            = appToUpdate
                                .OrgAppJoins
                                .SingleOrDefault(i => i.OrgID == org.ID);
                        context.Remove(orgToRemove);
                    }
                }
            }
        }

Затем я обрабатываю их в OnGetAsync в Edit.cshtml.cs:

public async Task<IActionResult> OnGetAsync(int? id)
        {
            this.TreeData = GetOrgTreeData();

            if (id == null)
            {
                return NotFound();
            }


            App = await _context.App
                .Include(i => i.OrgAppJoins).ThenInclude(i => i.Org)
                .Include(i => i.RoleAppJoins).ThenInclude(i => i.Role)
                .AsNoTracking()
                .FirstOrDefaultAsync(m => m.ID == id);

            if (App == null)
            {
                return NotFound();
            }
            PopulateAssignedAppRoleData(_context, App);
            PopulateAssignedAppOrgData(_context, App);
            return Page();
        }

и OnPostAsync

public async Task<IActionResult> OnPostAsync(int? id, string[] selectedOrgs, string[] selectedRoles)
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }


            var appToUpdate = await _context.App
                .Include(i => i.OrgAppJoins).ThenInclude(i => i.Org)
                .Include(i => i.RoleAppJoins).ThenInclude(i => i.Role)
                .FirstOrDefaultAsync(s => s.ID == id);


            if (await TryUpdateModelAsync<App>(
                 appToUpdate,
                 "app",   // Prefix for form value.
                   c => c.AppName, c => c.AppDescription, c => c.DisplayOrder))
            {
                UpdateAppOrgs(_context, selectedOrgs, appToUpdate);

                UpdateAppRoles(_context, selectedRoles, appToUpdate);

                await _context.SaveChangesAsync();
                return RedirectToPage("./Index");
            }

            UpdateAppOrgs(_context, selectedOrgs, appToUpdate);
            UpdateAppRoles(_context, selectedRoles, appToUpdate);

            PopulateAssignedAppOrgData(_context, App);
            PopulateAssignedAppRoleData(_context, App);
            return Page();

        }

. Это прекрасно работает при использовании множественных выпадающих списков иправильно читает и записывает во многие таблицы соединений.В данный момент я использую элементы управления кендо, но я рад использовать универсальные, если смогу найти решение своей проблемы.Мне нужно иметь древовидное представление для модели Org для отображения в виде множественного выбора, поэтому у меня есть два примера, которые я пытаюсь получить, которые ведут себя по-разному, DropDownTreeview не является необходимым, но на некоторых страницах это будет удобно, TreeView этосущественный.Первый - TreeView:

@(Html.Kendo().TreeView()
                           .Name("selectedOrgNames")
                           .DataTextField("OrgName")
                           .Checkboxes(checkboxes => checkboxes
                                      .Name("ischecked")
                                      .CheckChildren(true))
                           .HtmlAttributes(new { style = "width:100%" })
                           .DataSource(d => d
                               .Read(read =>
                                   read.Url("/Apps/Edit?handler=Read")
                               )
                           )
                        )

Второй - DropDownTreeview:

@(Html.Kendo().DropDownTree()
                               .Placeholder("Select ...")
                               .Name("selectedOrgs")
                               .DataTextField("OrgName")
                               .DataValueField("ID")
                               .Checkboxes(checkboxes => checkboxes
                                          .Name("ischecked")
                                          .CheckChildren(true))
                               .AutoClose(false)
                               .Value(Model.selectedOrgNames)
                               .HtmlAttributes(new { style = "width:100%" })
                               .DataSource(d => d
                                   .Read(read =>
                                       read.Url("/Apps/Edit?handler=Read")
                                   )
                               )
                        )

Оба примера читают источник данных отсюда в edit.cshtml.cs:

public IActionResult OnGetRead(int? id)
        {
            var result = from e in _context.Org
                                where id.HasValue ? e.ParentID == id : e.ParentID == null
                                select new
                                {
                                id = e.ID,
                                hasChildren = (from q in _context.Org
                                            where (q.ParentID == e.ID)
                                            select q
                                            ).Count() > 0,
                                OrgName = e.OrgName,
                                selected = (from s in _context.OrgAppJoin
                                            where (s.OrgID == e.ID) && (s.AppID == 2)// <--this works, this doesn't--> (s.AppID == app.ID) 
                                            select s
                                            ).Count() > 0,                           
                                ischecked = (from s in _context.OrgAppJoin
                                            where (s.OrgID == e.ID) && (s.AppID == 2)// <--this doesn't work, this doesn't either--> 
(s.AppID == app.ID)
                                            select s
                                            ).Count() > 0
                                };
            return new JsonResult(result);
        }

Моя первая проблема, вероятно, очень проста, я новичок в этой платформе: мне кажется, я не могу найти способ получить значение AppID со страницы в модуль OnGetRead (у меня жестко задан s.AppID== 2 в качестве тестового примера, чтобы увидеть, работает ли он) Я перепробовал все виды переменных и других методов.Идентификатор, передаваемый в OnPostAsync, а OnGetAsync - это идентификатор приложения, но идентификатор, передаваемый в OnGetRead, - это идентификатор организации, который является правильным и работает, но как использовать AppID со страницы для замены числа два вэта линия?где (s.OrgID == e.ID) && (s.AppID == 2)?

Моя вторая проблема - получение флажков для чтения и записи.DropDownTree выше записывает в базу данных правильно, но не читает и не заполняет флажки.Древовидное представление не заполняет флажки и не записывает данные в базу данных, однако оно СЧИТАЕТ выбранное значение из таблицы объединения для приложения № 2 (или любого другого числа, которое я вставляю вручную) в OnGetRead, и отображает различные цвета шрифтов и т. Д. Для правильных элементов.как выбрано, но не так, как проверено (aschecked может даже не быть действительным вызовом, но я не могу найти ссылку для этого).

Я чувствую, что я близко, но я пытался так долгозаставить это работать безрезультатно, в том числе и с телериком, который пытался помочь, но они не очень помогают в моделировании вашего собственного кода, только со статическими данными, и они, кажется, легки для приложения RazorБаза знаний и продолжайте давать примеры контроллеров с жестко закодированными данными.

Пожалуйста, сообщите, если мне нужно разделить это на два или более вопросов, но любая помощь будет высоко ценится

Спасибо

...