Я новичок в .NET 8 и создал форму, используя MVC, EF и X.PagedList. Моя форма имеет раскрывающийся список с множественным выбором. Я могу сохранить форму в базе данных. Раскрывающийся список «Множественный выбор» сохраняется в базе данных следующим образом ["abc", "xyz"]
.
Вот моя модель:
public partial class Bat
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public string? FirstName { get; set; }
public string? LastName { get; set; }
public IEnumerable<string>? MyMultiSelectList { get; set; } = null!;
}
Но когда я перехожу на страницу Index
, я получаю ошибку в строке IQueryable
ниже:
ArgumentException: выражение типа «System.Collections.Generic.IEnumerable
1[System.String]' cannot be used for parameter of type 'System.Collections.Generic.IList
1[System.String]» метода «System.Collections.Generic.IList1[System.String] PopulateList[String](System.Collections.Generic.IList
1[System.String], System.Collections.Generic.IList`1[System .String])» (параметр «arg0»).
Вот мой код метода Index
:
public IActionResult Index(int? page)
{
IQueryable<Bat> Bats = _context.Bats.AsQueryable();
int pageSize = 10;
int pageNumber = (page ?? 1);
return View(Bats.ToPagedList(pageNumber, pageSize));
}
Вот код моей Index
страницы:
@using X.PagedList
@using X.PagedList.Mvc.Core
@model X.PagedList.IPagedList<QII.Models.Initiative>
<table class = "table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.FirstName)
</th>
<th>
@Html.DisplayNameFor(model => model.LastName)
</th>
<th>
@Html.DisplayNameFor(model => model.MyMultiSelectList)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.FirstName)
</td>
<td>
@Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
@Html.DisplayFor(modelItem => item.MyMultiSelectList)
</td>
<td>
<a asp-action = "Edit" asp-route-id = "@item.Id">Edit</a> |
<a asp-action = "Details" asp-route-id = "@item.Id">Details</a> |
<a asp-action = "Delete" asp-route-id = "@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Если я изменю
public IEnumerable<string>? MyMultiSelectList { get; set; } = null!;
к
public string? MyMultiSelectList { get; set; } = null!;
ошибка исчезает, но в базе данных сохраняется только первый выбранный вариант «abc».
Может ли кто-нибудь сказать мне, как отобразить этот раскрывающийся список с множественным выбором в виде строки, например abc,xyz, на моей странице индекса и избавиться от этой ошибки?
Я проверил ссылку выше, вы имеете в виду реализацию множественного выбора, мне нужно создать новую ViewModel?
Вы можете попытаться преобразовать IEnumerable в строку, разделенную запятыми, в вашем представлении:
public partial class Bat
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public string? FirstName { get; set; }
public string? LastName { get; set; }
public IEnumerable<string>? MyMultiSelectList { get; set; } = null!;
// New property to get comma-separated string
public string MyMultiSelectListAsString
{
get
{
return MyMultiSelectList != null ? string.Join(", ", MyMultiSelectList) : string.Empty;
}
}
}
Обновите вид индексной страницы:
@using X.PagedList
@using X.PagedList.Mvc.Core
@model X.PagedList.IPagedList<QII.Models.Initiative>
<table class = "table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.FirstName)
</th>
<th>
@Html.DisplayNameFor(model => model.LastName)
</th>
<th>
@Html.DisplayNameFor(model => model.MyMultiSelectListAsString)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.FirstName)
</td>
<td>
@Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
@Html.DisplayFor(modelItem => item.MyMultiSelectListAsString)
</td>
<td>
<a asp-action = "Edit" asp-route-id = "@item.Id">Edit</a> |
<a asp-action = "Details" asp-route-id = "@item.Id">Details</a> |
<a asp-action = "Delete" asp-route-id = "@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Я попробовал то, что вы предложили, но та же ошибка.
Ваше представление также, кажется, объявляет модель типа IPagedList<QII.Models.Initiative>
, когда ваша линия return View(Bats.ToPagedList(pageNumber, pageSize));
доставляет PagedList<Bat>
, что также может быть проблемой.
Вы также можете уточнить, находится ли ошибка конкретно в строке IQueryable
или после return
.
Обновлено: Если это относится к строке IQueryable
, прочитайте следующее:
Ваша проблема, похоже, связана с тем, что где-то в этой операции ожидается объект IList
, но присутствует объект IEnumerable
.
Похоже, это связано не с PagedList
, а с вашим классом DbContext
, который может присутствовать, если вы новичок и используете подход «сначала код».
Вам следует проверить, содержит ли ваш класс DbContext
соответствующий тип свойства Bats (при обычном подходе, ориентированном на базу данных, это должно быть DbSet<Bat>
).
Если это уже так, то было бы полезно представить здесь свой DbContext
класс.
Я могу подтвердить, что ошибка возникает в строке IQueryable<Bat> Bats = _context.Bats.AsQueryable(); В моем DbCOntext у меня есть общедоступный виртуальный DbSet<Bat> Bats { get; набор; }
Я работаю с существующей базой данных.
@joegreen Я думаю, ваша ошибка может быть связана с базовым типом базы данных и тем, как считываются данные, но это выходит за рамки того, на что я могу ответить. Самый простой способ обойти вашу ошибку, вероятно, — изменить IEnumerable<string>? MyMultiSelectList в IList<string>?, так как это ожидаемый тип
Поскольку тип IEnumerable не может быть напрямую привязан к представлению. Если вы хотите отобразить значение в представлении, вы можете преобразовать IEnumerable в строку, создать модель представления, содержащую преобразованное строковое значение, а затем в методе Index контроллера преобразовать экземпляр Bat в экземпляр BatViewModel и использовать string.Join()
для преобразования IEnumerable<string>
в string
, после чего привяжите BatViewModel в представлении. Ниже приведен пример для справки.
Модель BatView:
public class BatViewModel
{
public Guid Id { get; set; }
public string? FirstName { get; set; }
public string? LastName { get; set; }
public string? MyMultiSelectList { get; set; }
}
Контроллер:
public IActionResult Index(int? page)
{
IQueryable<Bat> Bats = _context.Bats.AsQueryable();
int pageSize = 10;
int pageNumber = (page ?? 1);
var batViewModels = Bats
.Select(b => new BatViewModel
{
Id = b.Id,
FirstName = b.FirstName,
LastName = b.LastName,
MyMultiSelectList = b.MyMultiSelectList != null ? string.Join(",", b.MyMultiSelectList) : string.Empty
});
var pagedList = batViewModels.ToPagedList(pageNumber, pageSize);
return View(pagedList);
}
Вид:
@model X.PagedList.IPagedList<BatViewModel>
@using X.PagedList.Mvc.Core
<table class = "table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.FirstOrDefault().FirstName)
</th>
<th>
@Html.DisplayNameFor(model => model.FirstOrDefault().LastName)
</th>
<th>
@Html.DisplayNameFor(model => model.FirstOrDefault().MyMultiSelectList)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.FirstName)
</td>
<td>
@Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
@Html.DisplayFor(modelItem => item.MyMultiSelectList)
</td>
<td>
<a asp-action = "Edit" asp-route-id = "@item.Id">Edit</a> |
<a asp-action = "Details" asp-route-id = "@item.Id">Details</a> |
<a asp-action = "Delete" asp-route-id = "@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
МойДбКонтекст:
public class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options)
: base(options)
{
}
public DbSet<Bat> Bats { get; set; }
}
Результат:
И следует отметить, что использование DisplayNameFor
здесь вызовет исключение, которого можно избежать, используя FirstOrDefault()
.
Спасибо за объяснение, почему требуется ViewModel.
проверьте ListBox на наличие stackoverflow.com/questions/12176735/…