Невозможно преобразовать список в IEnumerable при объединении 2 общих списков MVC C # - PullRequest
0 голосов
/ 03 июня 2019

У меня есть 2 списка, сгенерированных LINQ с использованием ViewModels, которые я хотел бы объединить в один список и показать в виде данных на моем домашнем экране.Я проверил оба списка по отдельности, и каждый из них возвращает ожидаемые результаты.Я нашел несколько способов объединить списки, но я не могу объединить списки для отправки обратно на мой View.Может ли кто-нибудь помочь мне найти ответ здесь?

Используя приведенный ниже код, я имею в виду, что intellisense говорит мне, что list.AddRange(personnelList); и list.AddRange(nonPersonnelList); неверны.Проблема в том, что это cannot convert from Generic.List to Generic.IEnumerable.

Контроллер:

List<PersonnelViewModel> personnelList = (from p in db.Personnel
     where p.ActiveFG == true
     join pd in db.PersonnelDetail on p.ID equals pd.PersonnelID into pdGroup
     from pdItem in pdGroup.DefaultIfEmpty()
     join pos in db.Position on p.PrimaryPositionID equals pos.ID into posGroup
     from posItem in posGroup.DefaultIfEmpty()
     join d in db.Department on posItem.DepartmentID equals d.ID into dGroup
     from dItem in dGroup.DefaultIfEmpty()
     join l in db.Locations on p.PrimaryLocation equals l.ID into lGroup
     from lItem in lGroup.DefaultIfEmpty()
     join b in db.Building on lItem.BuildingID equals b.ID into bGroup
     from bItem in bGroup.DefaultIfEmpty()
     join f in db.FaxMachine on pdItem.FaxID equals f.ID into fGroup
     from fItem in fGroup.DefaultIfEmpty()
     select new PersonnelViewModel
     {
         ID = p.ID,
         DisplayName = p.DisplayName ?? string.Empty,
         EmailAddress = p.EmailAddress ?? string.Empty,
         PhotoLocation = p.PhotoLocation ?? string.Empty,
         PortNumber = pdItem.PhonePort ?? string.Empty,
         SwitchPort = pdItem.SwitchPort ?? string.Empty,
         PrimaryPositionTitle = posItem.PositionTitle ?? string.Empty,
         Supervisor = db.Personnel.Where(p => p.ID == posItem.SupervisorID).Select(n => n.DisplayName).FirstOrDefault(),
         PrimaryDepartmentName = dItem.DepartmentName ?? string.Empty,
         DirectoryAssistant = db.Personnel.Where(p => p.ID == dItem.DirectoryAssistantPositionID).Select(n => n.DisplayName).FirstOrDefault(),
         PrimaryRoomNumber = lItem.RoomNumber ?? string.Empty,
         PrimaryBuildingName = bItem.BuildingName ?? string.Empty,
         FaxNumber = fItem.Number ?? string.Empty,
         BuildingMonitor = (bool)pdItem.BuildingMonitor,
         CPRTrained = (bool)pdItem.CPRTrained,
         CPRTrainedExpirationDate = pdItem.CPRTrainedExpirationDate ?? default(DateTime),
         DirectDial = (bool)pdItem.DirectDial,
         AEDTrained = (bool)pdItem.DefibrillatorTrained,
         AEDTrainedExpirationDate = pdItem.DefibrillatorTrainedExpirationDate ?? default(DateTime),
         PrimaryExtension = (int)pdItem.Extension,
         NotaryPublic = (bool)pdItem.NotaryPublic,
         NotaryPublicExpirationDate = pdItem.NotaryPublicExpirationDate ?? default(DateTime),
         ActiveFG = (bool)p.ActiveFG,
         Person = true,
         LastUpdatedBy = p.LastUpdatedBy,
         LastUpdatedDate = p.LastUpdatedDate.Value,
     }).ToList();

List<NonPersonnelViewModel> nonPersonnelList = (from np in db.NonPersonnel
    where np.ActiveFG == true
    join npt in db.NonPersonnelTypes on np.NonPersonnelTypesID equals npt.ID into nptGroup
    from nptItem in nptGroup.DefaultIfEmpty()
    join dpt in db.Department on np.DepartmentID equals dpt.ID into dptGroup
    from dptItem in dptGroup.DefaultIfEmpty()
    join a in db.Area on dptItem.AreaID equals a.ID into aGroup
    from aItem in aGroup.DefaultIfEmpty()
    join div in db.Division on aItem.DivisionID equals div.ID into divGroup
    from divItem in divGroup.DefaultIfEmpty()
    join l in db.Locations on np.LocationID equals l.ID into lGroup
    from lItem in lGroup.DefaultIfEmpty()
    join b in db.Building on lItem.BuildingID equals b.ID into bGroup
    from bItem in bGroup.DefaultIfEmpty()
    join s in db.Sites on bItem.SiteID equals s.ID into sGroup
    from sItem in sGroup.DefaultIfEmpty()

    select new NonPersonnelViewModel
    {
        ID = np.ID,
        NonPersonnelDescription = nptItem.NonPersonnelDescription ?? string.Empty,
        DepartmentName = dptItem.DepartmentName ?? string.Empty,
        DivisionName = divItem.DivisionName ?? string.Empty,
        AreaName = aItem.AreaName ?? string.Empty,
        Site = string.Concat((sItem.AddressLine1 ?? string.Empty) + Environment.NewLine + (sItem.AddressLine2 ?? string.Empty) + Environment.NewLine +
        (sItem.City ?? string.Empty) + " " + (sItem.State ?? string.Empty) + ", " + (sItem.Zip ?? string.Empty)),
        Switchboard = sItem.Switchboard ?? string.Empty,
        DirectoryAssistant = db.Personnel.Where(p => p.ID == dptItem.DirectoryAssistantPositionID).Select(n => n.DisplayName).FirstOrDefault(),
        RoomNumber = lItem.RoomNumber ?? string.Empty,
        BuildingName = bItem.BuildingName ?? string.Empty,
        Person = false,
        ActiveFG = (bool)np.ActiveFG,
        LastUpdatedBy = np.LastUpdatedBy,
        LastUpdatedDate = np.LastUpdatedDate.Value,
    }).ToList();

List<HomeViewModel> list = new List<HomeViewModel>();
list.AddRange(personnelList);
list.AddRange(nonPersonnelList);
// combine lists to show in master list on home page
return View(list);

ViewModel:

public class HomeViewModel
{
    public List<PersonnelViewModel> PersonnelList { get; set; }
    public List<NonPersonnelViewModel> NonPersonnelList { get; set; }
}

Теперь представление - это то, куда я звоню @model IEnumerable<Models.HomeViewModel, но это прекрасно работает, когда я просто хочу отобразить одиниз 2 списков.Я подумал, что, возможно, обновление

public List<PersonnelViewModel> PersonnelList { get; set; }
public List<NonPersonnelViewModel> NonPersonnelList { get; set; } 

и добавление .AsEnumerable к обоим запросам поможет, но у меня все еще есть то же сообщение об ошибке, что я не собираюсь конвертировать из List в IEnumerable.

Добавление.AsEnumerable() для каждого из .AddRange для окончательного списка генерирует только ошибку, говорящую cannot convert from Generic.IEnumerable<PersonnelViewModel> to Generic.IEnumerable<HomeViewModel>

Возможно ли это сделать?Мне нужно, чтобы все записи о персонале и не о персонале отображались на одной и той же странице, так как я делаю онлайн-каталог, так что это должно быть выполнено так или иначе.Я просто надеюсь, что я на правильном пути, и мне не нужно много переделывать.Любая помощь приветствуется!

ОБНОВЛЕНИЕ с рабочим кодом:

Контроллер:

public ActionResult Index()
    {
        List<IndexViewModel> personnelList = (from p in db.Personnel
                             where p.ActiveFG == true
                             join pd in db.PersonnelDetail on p.ID equals pd.PersonnelID into pdGroup
                             from pdItem in pdGroup.DefaultIfEmpty()
                             join pos in db.Position on p.PrimaryPositionID equals pos.ID into posGroup
                             from posItem in posGroup.DefaultIfEmpty()
                             join d in db.Department on posItem.DepartmentID equals d.ID into dGroup
                             from dItem in dGroup.DefaultIfEmpty()
                             join l in db.Locations on p.PrimaryLocation equals l.ID into lGroup
                             from lItem in lGroup.DefaultIfEmpty()
                             join b in db.Building on lItem.BuildingID equals b.ID into bGroup
                             from bItem in bGroup.DefaultIfEmpty()
                             join f in db.FaxMachine on pdItem.FaxID equals f.ID into fGroup
                             from fItem in fGroup.DefaultIfEmpty()
                             select new IndexViewModel
                             {
                                 ID = p.ID,
                                 DisplayName = p.DisplayName ?? string.Empty,
                                 EmailAddress = p.EmailAddress ?? string.Empty,
                                 PhotoLocation = p.PhotoLocation ?? string.Empty,
                                 PortNumber = pdItem.PhonePort ?? string.Empty,
                                 SwitchPort = pdItem.SwitchPort ?? string.Empty,
                                 PositionTitle = posItem.PositionTitle ?? string.Empty,
                                 Supervisor = db.Personnel.Where(p => p.ID == posItem.SupervisorID).Select(n => n.DisplayName).FirstOrDefault(),
                                 DepartmentName = dItem.DepartmentName ?? string.Empty,
                                 DirectoryAssistant = db.Personnel.Where(p => p.ID == dItem.DirectoryAssistantPositionID).Select(n => n.DisplayName).FirstOrDefault(),
                                 RoomNumber = lItem.RoomNumber ?? string.Empty,
                                 BuildingName = bItem.BuildingName ?? string.Empty,
                                 FaxNumber = fItem.Number ?? string.Empty,
                                 BuildingMonitor = (bool)pdItem.BuildingMonitor,
                                 CPRTrained = (bool)pdItem.CPRTrained,
                                 CPRTrainedExpirationDate = pdItem.CPRTrainedExpirationDate ?? default(DateTime),
                                 DirectDial = (bool)pdItem.DirectDial,
                                 AEDTrained = (bool)pdItem.DefibrillatorTrained,
                                 AEDTrainedExpirationDate = pdItem.DefibrillatorTrainedExpirationDate ?? default(DateTime),
                                 Extension = (int)pdItem.Extension,
                                 NotaryPublic = (bool)pdItem.NotaryPublic,
                                 NotaryPublicExpirationDate = pdItem.NotaryPublicExpirationDate ?? default(DateTime),
                                 ActiveFG = (bool)p.ActiveFG,
                                 Person = true,
                                 LastUpdatedBy = p.LastUpdatedBy,
                                 LastUpdatedDate = p.LastUpdatedDate.Value,
                             }).ToList();

        List<IndexViewModel> nonPersonnelList = (from np in db.NonPersonnel
                                where np.ActiveFG == true
                                join npt in db.NonPersonnelTypes on np.NonPersonnelTypesID equals npt.ID into nptGroup
                                from nptItem in nptGroup.DefaultIfEmpty()
                                join dpt in db.Department on np.DepartmentID equals dpt.ID into dptGroup
                                from dptItem in dptGroup.DefaultIfEmpty()
                                join a in db.Area on dptItem.AreaID equals a.ID into aGroup
                                from aItem in aGroup.DefaultIfEmpty()
                                join div in db.Division on aItem.DivisionID equals div.ID into divGroup
                                from divItem in divGroup.DefaultIfEmpty()
                                join l in db.Locations on np.LocationID equals l.ID into lGroup
                                from lItem in lGroup.DefaultIfEmpty()
                                join b in db.Building on lItem.BuildingID equals b.ID into bGroup
                                from bItem in bGroup.DefaultIfEmpty()
                                join s in db.Sites on bItem.SiteID equals s.ID into sGroup
                                from sItem in sGroup.DefaultIfEmpty()

                                select new IndexViewModel
                                {
                                    ID = np.ID,
                                    DisplayName = nptItem.NonPersonnelDescription ?? string.Empty,
                                    DepartmentName = dptItem.DepartmentName ?? string.Empty,
                                    DivisionName = divItem.DivisionName ?? string.Empty,
                                    AreaName = aItem.AreaName ?? string.Empty,
                                    Site = string.Concat((sItem.AddressLine1 ?? string.Empty) + Environment.NewLine + (sItem.AddressLine2 ?? string.Empty) + Environment.NewLine +
                                    (sItem.City ?? string.Empty) + " " + (sItem.State ?? string.Empty) + ", " + (sItem.Zip ?? string.Empty)),
                                    Switchboard = sItem.Switchboard ?? string.Empty,
                                    DirectoryAssistant = db.Personnel.Where(p => p.ID == dptItem.DirectoryAssistantPositionID).Select(n => n.DisplayName).FirstOrDefault(),
                                    RoomNumber = lItem.RoomNumber ?? string.Empty,
                                    BuildingName = bItem.BuildingName ?? string.Empty,
                                    Person = false,
                                    ActiveFG = (bool)np.ActiveFG,
                                    LastUpdatedBy = np.LastUpdatedBy,
                                    LastUpdatedDate = np.LastUpdatedDate.Value,
                                }).ToList();

        var list = new List<IndexViewModel>(personnelList);            
        list.AddRange(nonPersonnelList);
        // combine lists to show in master list on home page
        return View(list);
    }

ViewModel:

public class IndexViewModel
{
    // personnel //

    public string NamePrefix { get; set; }
    public string FirstName { get; set; }
    public string MiddleName { get; set; }
    public string LastName { get; set; }
    public string NameSuffix { get; set; }
    public string UserName { get; set; }
    public string FullName { get; set; }
    public string PhotoLocation { get; set; }
    public string PositionTitle { get; set; }
    public string SecondaryPositionTitle { get; set; }
    public string SecondaryDepartmentName { get; set; }
    public string SecondaryDivisionName { get; set; }
    public string SecondaryAreaName { get; set; }
    public int SecondaryExtension { get; set; }
    public string SecondaryBuildingName { get; set; }
    public string SecondaryRoomNumber { get; set; }
    public string EmailAddress { get; set; }
    public string Supervisor { get; set; }
    public string SecondaryLocation { get; set; }
    public string FaxNumber { get; set; }
    public int Voicemail { get; set; }
    public string PortNumber { get; set; }
    public string SwitchPort { get; set; }
    public bool DirectDial { get; set; }
    public bool BuildingMonitor { get; set; }
    public bool NotaryPublic { get; set; }
    public DateTime NotaryPublicExpirationDate { get; set; }
    public bool CPRTrained { get; set; }
    public DateTime CPRTrainedExpirationDate { get; set; }
    public bool AEDTrained { get; set; } // DefibrillatorTrained
    public DateTime AEDTrainedExpirationDate { get; set; } // DefibrillatorTrainedExpirationDate


    // both //

    public int ID { get; set; }
    public string DisplayName { get; set; }
    public string DepartmentName { get; set; }
    public string DivisionName { get; set; }
    public string AreaName { get; set; }
    public int Extension { get; set; }
    public string BuildingName { get; set; }
    public string RoomNumber { get; set; }
    public string Location { get; set; }
    public string Site { get; set; }
    public string Switchboard { get; set; }
    public string DirectoryAssistant { get; set; }
    public string MailboxLocation { get; set; }
    public bool ActiveFG { get; set; }
    public bool Person { get; set; }
    public string LastUpdatedBy { get; set; }
    public DateTime LastUpdatedDate { get; set; }
}

1 Ответ

1 голос
/ 04 июня 2019

Похоже, вы пытаетесь заставить два списка в модель представления для представления, которое ожидает список. Хотя использование списка в качестве модели представления является обычной практикой, я считаю, что в долгосрочной перспективе его не очень легко обслуживать и что лучше создать класс модели представления для конкретного вида в качестве контейнера с самого начала. Всегда есть вероятность, что вам придется добавить что-то в модель представления позже, и ее легче адаптировать, если все, что вам нужно сделать, это добавить свойство.

Дело в том, что ты почти у цели. У вас есть HomeViewModel, который имеет оба списка в качестве свойств. Все, что вам нужно сделать (по крайней мере, в методе действия), это заполнить свойства и передать их представлению.

HomeViewModel viewModel = new HomeViewModel()
{
    PersonnelList = personnelList,
    NonPersonnelList = nonPersonnelList 
};

return View(viewModel);

По вашему мнению, измените тип модели, и вы получите Model.PersonnelList и Model.NonPersonnelList.

@model <whatever the namespace is>.HomeViewModel

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

@foreach (var personnel in Model.PersonnelList)
{
    @* Display 'personnel' data *@
}

@foreach (var nonPersonnel in Model.NonPersonnelList)
{
    @* Display 'nonPersonnel' data *@
}

В качестве примечания, предположив, что это метод действия Index в HomeController, я предлагаю переименовать HomeViewModel в IndexViewModel и поместить его в папку HomeModels в папке Models , Такой способ организации классов поможет сохранить организованность просмотра моделей и связанных классов.


Немного компромисса

Если вы действительно нуждаетесь в них в одном списке, это не будет так просто, но это возможно.

Ваш список должен быть объявлен для хранения экземпляров, которые можно назначить общему типу. List<object> сработает для того, что вы имеете сейчас, потому что они по сути не имеют ничего общего. Это не так хорошо.

Вы можете объявить базовый класс, например BasePersonViewModel и перенесите в него некоторые общие свойства, такие как ID, ActiveFG, Person, LastUpdatedBy и LastUpdatedDate. Это позволит вам что-то делать со всеми из них, например сортировать по LastUpdatedDate. (До сих пор неясно, является ли «внештатный сотрудник» человеком другого типа или чем-то, что не является человеком, поэтому имя может быть неправильным - просто потерпите меня.)

IEnumerable<BasePersonViewModel> viewModel = personnel.AsEnumerable<BasePerson>()
    .Concat(nonPersonnel)
    .OrderByDescending(p => p.LastUpdatedDate);

return View(viewModel);

Независимо от того, создаете ли вы собственный базовый класс, каждый элемент в списке должен быть приведен к правильному типу, чтобы использовать его свойства.

@* Assuming Model is List<BasePersonViewModel> *@
@foreach (BasePersonViewModel item in Model)
{
    @* display common data such as item.ID *@

    @if (item is PersonnelViewModel personnel)
    {
        @* Display 'personnel' data *@
    }
    else if (item is NonPersonnelViewModel nonPersonnel)
    {
        @* Display 'nonPersonnel' data *@
    }
}

Сказав это, вы должны использовать отдельные списки, если это возможно.

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