【发布时间】:2021-05-11 10:01:54
【问题描述】:
我有一个管理区域(区域)土壤的小型应用程序。 Zone 有 Soils 可以与之关联。
当我创建区域时,我可以选择土壤然后保存,但是一旦创建,当我在修改中打开它并点击“保存”时,没有其他任何东西,它会抛出我:
SqlException:违反主键约束“PK_SoilZone”。 无法在对象“dbo.SoilZone”中插入重复键。复制品 键值为 (1, 1)。
景色是这样的
商务舱:
public class Zone
{
public string Name { get; set; }
public int CountryId { get; set; }
public Country Country { get; set; }
#region navigation props
public ICollection<Soil> Soils { get; set; } = new List<Soil>();
public List<SoilZone> SoilZones { get; set; } = new List<SoilZone>();
#endregion
}
DTO 对象(ViewModel):
public class ZoneDTO
{
public string Name { get; set; }
public int CountryId { get; set; }
public string CountryName { get; set; }
public int[] AvailableSoilIds { get; set; } = new int[] { };
public int[] SoilIds { get; set; } = new int[] { };
public string[] SoilNames { get; set; } = new string[] { };
}
自动映射:
CreateMap<Zone, ZoneDTO>()
.ForMember(p => p.CountryName, o => o.MapFrom(p => p.Country.Name))
.ForMember(p => p.SoilIds, o => o.MapFrom(p => p.Soils.Select(s => s.Id).ToArray()))
.ForMember(p => p.SoilNames, o => o.MapFrom(p => p.Soils.Select(s => s.Name).ToArray()))
.ReverseMap();
查看:
@model MyApp.Web.DTOs.ZoneDTO
<form asp-action="Edit">
<div>
<label asp-for="Name"></label>
<input asp-for="Name" />
</div>
<div>
<label asp-for="CountryId" class="control-label"></label>
<select asp-for="CountryId" class="form-control" asp-items="ViewBag.CountryId"></select>
<label asp-for="SoilIds"></label>
<select asp-for="AvailableSoilIds" asp-items="ViewBag.AvailableSoils" multiple="multiple"></select>
<a href="#" id="addSoil">Add</a>
<select asp-for="SoilIds" asp-items="ViewBag.Soils" multiple="multiple"></select>
<a href="#" id="removeSoil">Remove</a>
</div>
<input type="hidden" asp-for="Id" />
<div>
<input type="submit" value="Save" />
<a asp-action="Index" >Cancel</a>
</div>
</form>
控制器的编辑:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, ZoneDTO zoneDto)
{
if (ModelState.IsValid)
{
try
{
var zone = _mapper.Map<Zone>(zoneDto);
// from here I am not sure if it's OK <<<<<<<<<<<<
zone.Soils.Clear();
foreach (var soilId in zoneDto.SoilIds)
{
var soil = _context.Soils.Where(s => s.Id == soilId).FirstOrDefault();
zone.Soils.Add(soil);
}
zone.Country = _context.Country.Find(zoneDto.CountryId);
_context.Update(zone);
await _context.SaveChangesAsync();
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
}
catch (DbUpdateConcurrencyException)
{
if (!ZoneExists(zoneDto.Id)) {
return NotFound();
}
else {
throw;
}
}
return RedirectToAction(nameof(Index));
}
var dto = _mapper.Map<ZoneDTO>(zoneDto);
ViewData["CountryId"] = new SelectList(_context.Country, "Id", "Code", zoneDto.CountryId);
ViewData["AvailableSoils"] = new MultiSelectList(_context.Soils, "Id", "Name", dto.SoilIds);
return View(dto);
}
以及 EF 配置:
public override void Configure(EntityTypeBuilder<Zone> builder)
{
base.Configure(builder);
builder.HasIndex(p => p.Nom);
builder
.HasOne(p => p.Country)
.WithMany(p => p.Zones)
.HasForeignKey(p => p.CountryId)
.IsRequired();
builder
.HasMany(p => p.Soils)
.WithMany(p => p.Zones)
.UsingEntity<SoilZone>(
p => p
.HasOne(p => p.Soil)
.WithMany(p => p.SoilZones)
.HasForeignKey(p => p.SoilId),
p => p
.HasOne(p => p.Zone)
.WithMany(p => p.SoilZones)
.HasForeignKey(p => p.ZoneId),
p =>
{
p.HasKey(k => new { k.ZoneId, k.SoilId });
});
}
【问题讨论】:
-
您可能会发现这个答案很有帮助 - stackoverflow.com/a/66043831/446519
标签: c# entity-framework asp.net-core entity-framework-core ef-core-5.0