【问题标题】:Can't save multiple selections in select list - asp.net core web app razor pages无法在选择列表中保存多个选择 - asp.net core web app razor pages
【发布时间】:2020-01-07 15:33:24
【问题描述】:

在这里我可以在创建页面上绑定多选列表。

<select id="multiple" asp-for="SecurityLog.Officer" multiple="multiple" class="selectpicker form-control" asp-items="ViewBag.Officer">
</select>

public IActionResult OnGetAsync()
{                    
     ViewData["Officer"] = new SelectList(_context.Officer.Where(a => a.Active == "Y"), "ID", "FullName");

     return Page();
}

我遇到的最大问题是我正在尝试编辑/发布值,并且在我的模型中没有直接绑定到的字段。

我在这里找到了一个很好的例子,但它只向您展示了如何保存 1 个选择。 https://www.learnrazorpages.com/razor-pages/forms/select-lists

我的 SecurityLog 模型有这个

public virtual Officer Officer { get; set; }

我的军官模型有这个

namespace SecurityCore.Models
{
    public class Officer
    {
        [Required]
        public int ID { get; set; }

        [Required]
        [Display(Name = "Officer's First Name")]
        public string FirstName { get; set; }

        [Required]
        [Display(Name = "Officer's Last Name")]
        public string LastName { get; set; }

        [Display(Name = "Officer's Name")]
        public string FullName { get; set; }

        [Required]
        public string Active { get; set; }        
    }
}

我没有 SecurityLogOfficer 模型。我需要一个吗?

这是我的数据库架构和示例结果

任何帮助将不胜感激!

* 更新 *

感谢您建议绑定到列表并将 asp-for 更改为该列表。这是我更新的代码。 SelectedOfficerIds 确实存储了选定的 id。

<select id="multiple" asp-for="SelectedOfficerIds" multiple="multiple" class="selectpicker form-control" asp-items="ViewBag.Officer">    
</select>

我要发布到两个不同的数据库(1 条记录应该到 SecurityLog,多条到 SecurityLogOfficer),但由于我调用了 savechanes() 两次,它实际上是在将多条记录发布到 SecurityLog db 和第二个 for 循环保存我收到一个错误

当 IDENTITY_INSERT 设置为 OFF 时,无法为表“SecurityLogOfficer”中的标识列插入显式值

_context.SecurityLog.Add(SecurityLog);
//We need to ensure we have the ID of the newly posted event
_context.SaveChanges();

int tempSecurityLogID = SecurityLog.ID;

for (int i = 0; i < SelectedOfficerIds.Length; i++)
{                
     SecurityLogOfficer.SecurityLogID = tempSecurityLogID;
     SecurityLog = null;

     SecurityLogOfficer.OfficerID = SelectedOfficerIds[i];
     _context.SecurityLogOfficer.Add(SecurityLogOfficer);                
     await _context.SaveChangesAsync();
}            

Message = "Entry added successfully!";

有没有办法清除 SecurityLog 的 _context,所以我只发布一次,我该如何解决 identity_insert 问题?数据库 SecurityLogOfficer 已启用身份插入。

2020 年 1 月 9 日更新

@XingZou - 感谢您的快速回复。我尝试执行你的步骤,一切都很完美!!!

如果您不介意,我还有一个问题?我试图在编辑页面上获取选定值的列表,但无法设置这些值。这是我迄今为止尝试过的......

这是我的编辑页面模型...

[BindProperty] 
public MultiSelectList GetExistingSelectedOfficerIds { get; set; }

public async Task<IActionResult> OnGetAsync(int? id)
{
    var i = _context.SecurityLogOfficer.Where(a => a.SecurityLogID == SecurityLog.ID);

        SecurityLogOfficers.AddRange(i);

        int[] GetExistingSelectedOfficerIds = new int[SecurityLogOfficers.Count];

        int itemCount = 0;
        foreach (var item in SecurityLogOfficers)
        {                
            GetExistingSelectedOfficerIds[itemCount] = item.OfficerID;
            itemCount++;
        }

        return Page();
}

这是我的编辑剃须刀页面...

<select id="multiple" asp-for= "GetExistingSelectedOfficerIds" multiple="multiple" class="selectpicker form-control" asp-items="ViewBag.Officer">
</select>
<span asp-validation-for="GetExistingSelectedOfficerIds" class="text-danger"></span>

【问题讨论】:

  • 你能发布你用来从选择列表中读取数据的代码吗?谢谢。
  • 我认为您正在寻找的内容已经在页面顶部。可能是我误会了?
  • SecurityLog和Officer是什么关系?一对多还是多对多?asp-for="SecurityLog.Officer"没用,因为你选择的是officer ID列表
  • SecurityLog和Officer之间没有直接关系。 SecurityLog 和 SecurityLogOfficer 之间是一对多的关系,SecurityLogOfficer 和Officer 之间是多对一的关系。

标签: c# sql asp.net-core razor razor-pages


【解决方案1】:

您需要将下拉列表绑定到 int 列表而不是 object。

在 PageModel 中,添加一个存储所有选定 Id 的新属性:

[BindProperty]
public int[] SelectedOfficerIds { get; set; }

在 Razor 页面上,将多选绑定到SelectedOfficerIds

<form method="post">
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    <div class="form-group">
        <label asp-for="SecurityLog.EventDate" class="control-label"></label>
        <input asp-for="SecurityLog.EventDate" class="form-control" />
        <span asp-validation-for="SecurityLog.EventDate" class="text-danger"></span>
    </div>
    <div class="form-group">
        <label class="control-label">Officers</label>
        <select id="multiple" asp-for="SelectedOfficerIds" multiple="multiple" class="selectpicker form-control" asp-items="ViewBag.Officer">
        </select>
    </div>

    <div class="form-group">
        <input type="submit" value="Create" class="btn btn-primary" />
    </div>
</form>

当您提交表单时,您将在您的 post handler 中获得新的 SecurityLog 官员 ID 列表。

2020 年 1 月 9 日更新

SecurityLog 和Officer 之间没有直接关系。 SecurityLog 和 SecurityLogOfficer 是一对多的关系,SecurityLogOfficer 和Officer 是多对一的关系。

根据你的描述,在SecurityLogOfficer之间是many-to-many relationships。 1.删​​除SecurityLogOfficerID,现在使用复合键

public class SecurityLogOfficer
{
    public int SecurityLogID { get; set; }
    public SecurityLog SecurityLog { get; set; }

    public int OfficerID { get; set; }
    public Officer Officer { get; set; }
}
public class Officer
{
    public int ID { get; set; }

    //other properties

    public List<SecurityLogOfficer> SecurityLogOfficers { get; set; }
}

public class SecurityLog
{
    public int ID { get; set; }

    //other properties

    public virtual List<SecurityLogOfficer> SecurityLogOfficers { get; set; }
}

2.配置多对多关系,如下所示。

public class RazorpagesCoreContext : DbContext
{
    public RazorpagesCoreContext (DbContextOptions<RazorpagesCoreContext> options)
        : base(options)
    {
    }


    public DbSet<Officer> Officer { get; set; }
    public DbSet<SecurityLog> SecurityLog { get; set; }
    public DbSet<SecurityLogOfficer> SecurityLogOfficer { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<SecurityLogOfficer>()
            .HasKey(t => new { t.SecurityLogID, t.OfficerID });

        modelBuilder.Entity<SecurityLogOfficer>()
            .HasOne(pt => pt.SecurityLog)
            .WithMany(p => p.SecurityLogOfficers)
            .HasForeignKey(pt => pt.SecurityLogID);

        modelBuilder.Entity<SecurityLogOfficer>()
            .HasOne(pt => pt.Officer)
            .WithMany(t => t.SecurityLogOfficers)
            .HasForeignKey(pt => pt.OfficerID);
    }
}

3.添加迁移和更新数据库。

有没有办法清除 SecurityLog 的 _context 所以我只发布一次

4.在您的 PageModel 中,保存如下数据

[BindProperty]
public SecurityLog SecurityLog { get; set; }

public List<SecurityLogOfficer> SecurityLogOfficers { get; set; } = new List<SecurityLogOfficer>();

[BindProperty]
public int[] SelectedOfficerIds { get; set; }

public async Task<IActionResult> OnPostAsync()
    {
        _context.SecurityLog.Add(SecurityLog);
        foreach (var id in SelectedOfficerIds)
        {
            var item = new SecurityLogOfficer()
            {
                SecurityLog = SecurityLog,
                Officer = await _context.Officer.FirstOrDefaultAsync(s => s.ID == id),
            };
            SecurityLogOfficers.Add(item);
        }
        _context.SecurityLogOfficer.AddRange(SecurityLogOfficers);
        await _context.SaveChangesAsync();

        return RedirectToPage("./Index");
    }

2020 年 1 月 10 日更新

要在编辑页面中获取多个选定值,请在获取处理程序中 return Page() 之前使用以下代码

ViewData["Officer"] = new MultiSelectList(_context.Officers.Where(a => a.Active == "Y"), "ID", "FullName", GetExistingSelectedOfficerIds);

【讨论】:

  • 我用更新的代码和问题编辑了您的答案,但我正在等待同行评审批准。非常感谢您的帮助!
  • @RobC 我刚刚拒绝了你的编辑,如果你想更新自己的代码并提出问题,你可以通过editing你的问题来这样做
  • 对不起...@XingZou 我更新了我原来的问题。
  • @Rob C 我认为你想要的只是 ef core 中的多对多关系。我更新了我的答案。
  • @Xing Zou - 您的代码运行良好!非常感谢!如果您不介意,我确实在原始问题中添加了 1 个额外的后续问题。 (2020 年 1 月 9 日更新)。非常感谢您的帮助,因为我几个月前才开始学习剃须刀页面。
【解决方案2】:

您没有共享完整的创建页面模型。里面有没有类似以下的东西:

public MultiSelectList Officer { get; set; }

我相信您将能够使用来自军官模型的军官信息来填充它。

【讨论】:

  • 根据建议的答案,我现在使用 public int[] SelectedOfficerIds { get;放; }
猜你喜欢
  • 2022-01-06
  • 2020-04-20
  • 2019-02-28
  • 2023-02-04
  • 2020-02-03
  • 1970-01-01
  • 1970-01-01
  • 2019-06-13
  • 2018-10-16
相关资源
最近更新 更多