上下文
通过 Javascript,我对控制器进行 ajax 调用以更新实体“Owner”。控制器使用服务来处理请求,并相应地更新实体。在服务更新方法中我还更新了“Owner”的相关数据,并且在某些情况下我还添加了一个新的实体“Owner”。
问题
这里(在服务中),由于某种原因,
update
方法被多次调用。查看 ThreadPool
列表,它显示多个工作线程处于活动状态。由于这个问题,我最终添加了多个重复的行并更新了不一致的数据(缺少某些字段 - 例如裤子和夹克)。我希望它只运行一次。
如果我只执行
EDIT
操作,不会发生任何不好的事情。
如果我执行 ADD 操作,然后执行 EDIT 操作,则编辑将运行 2 次,在数据库中再添加 2 行。
如果我执行 2 次或更多(让我们称这个数字为 N)ADD 操作,然后执行编辑操作,则编辑将运行 N x 2 次,创建 N x 2 重复行。
我尽可能地减少了代码。它有点长,但我不想排除任何可能实际上是罪魁祸首的情况。
如果提供的最小化代码还不够,我还可以为我们之间的代码向导提供对存储库的访问。请帮我。我真的不知道还有什么可以尝试让它发挥作用。
使用的堆栈:.NET Core 2.2、最新的 jQuery、MySQL、pomelo、EF Core
我已经尝试过的东西:
Scoped
Transient
Transient
threadPool.MaxLimit(1,1)
前端:
<script>
$(document).one("click", "#buttonId", function () {
$(this).attr("disabled", "disabled");
var result = validator.validate(validator);
if (result.formIsValid) {
$.ajax({
type: "POST",
url: "/controllerName/Edit",
data: $('#editForm').serialize(),
dataType: "json",
success: function (response) {
CloseModalById('editModal');
ShowHeaderAlert(response, "success", 5000);
$('#ownerListState').change();
},
error: function (error) {
CloseModalById('editModal');
swalErrorTimer(error.responseText, 7000);
}
});
} else {
updateUi(result.validationResults, "form-group", "error_span");
}
});
</script>
控制器:
public OwnerController(IOwnerService ownerService,IMapper mapper)
{
_ownerService = ownerService;
_mapper = mapper;
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditModal(OwnerViewModel ownerVM)
{
try
{
var dto = _mapper.Map<OwnerDto> ownerVM);
var result = _ownerService.UpdateOwner(dto);
if (result.Successful)
{
return Ok(JsonConvert.SerializeObject("Successfully updated!"));
}
return BadRequest("Something went wrong!");
}
catch (Exception e)
{
Log.Error(e, "Something went wrong!");
return BadRequest("Something went wrong!");
}
}
服务:
public OwnerService(IOwnerRepository ownerRepository, ICatRepository catRepository, ICatService catService, IMapper mapper)
{
_ownerRepository = ownerRepository;
_catRepository = catRepository;
_catService = catService;
_mapper = mapper;
}
public Result<OwnerDto> UpdateOwner(OwnerDto ownerDto)
{
try
{
var oldOwner = ownerDto.Copy();
// case: changed status in other than AtWork => empty the position for this set
if (ownerDto.LocationId != null && ownerDto.Status != "AtWork")
{
_catService.UpdateCatPosition(ownerDto.LocationId.Value, ownerDto.Biscuits, PositionEnum.InTheHouse);
}
// case: was AtWork, will be in raft => position changed
if (ownerDto.LocationId != null && ownerDto.Status == "AtWork"
&& ownerDto.LocationId != null
&& ownerDto.Biscuits == ownerDto.OldNrOfBiscuits)
{
_catService.UpdateCatPosition(ownerDto.LocationId.Value, ownerDto.Biscuits, PositionEnum.InTheHouse);
_catService.UpdateCatPosition(ownerDto.LocationId.Value, ownerDto.Biscuits, PositionEnum.InTheGarden);
}
// case: no change for position but change for nr of biscuits =>
if (ownerDto.LocationId != null && ownerDto.Status == "AtWork"
&& ownerDto.Biscuits != ownerDto.OldNrOfBiscuits
&& ownerDto.LocationId == null)
{
ownerDto.LocationId = ownerDto.LocationId;
// case we have added some new anv to this set => we have to also update the nr inside position
if (ownerDto.Biscuits > ownerDto.OldNrOfBiscuits)
{
var newNrBiscuits = ownerDto.Biscuits - ownerDto.OldNrOfBiscuits;
var catPosition = PositionEnum.InTheGarden;
_catService.UpdateCatPosition(ownerDto.LocationId.Value, newNrBiscuits, catPosition);
}
// case we have removed some biscuits from this owner => we have to also update the nr for the cat
if (ownerDto.Biscuits < ownerDto.OldNrOfBiscuits)
{
var newNrBiscuits = ownerDto.OldNrOfBiscuits - ownerDto.Biscuits;
var catPosition = PositionEnum.InTheHouse;
_catService.UpdateCatPosition(ownerDto.LocationId.Value, newNrBiscuits, catPosition);
}
}
// case: was AtWork, will be AtWork, Position changed, Biscuits changed
if (ownerDto.LocationId != null && ownerDto.Status == "AtWork"
&& ownerDto.LocationId != null
&& ownerDto.LocationId != ownerDto.LocationId
&& ownerDto.Biscuits != ownerDto.OldNrOfBiscuits)
{
var newNrBiscuits = ownerDto.OldNrOfBiscuits -(ownerDto.OldNrOfBiscuits - ownerDto.Biscuits);
var catPosition = PositionEnum.InTheGarden;
_catService.UpdateCatPosition(ownerDto.LocationId.Value, newNrBiscuits, catPosition);
}
// case: was not AtWork but will be AtWork
if (ownerDto.LocationId != null && ownerDto.LocationId == null)
{
_catService.UpdateCatPosition(ownerDto.LocationId.Value, ownerDto.Biscuits, PositionEnum.InTheGarden);
}
if (ownerDto.LocationId != null)
{
var catPosition = catRepository.GetPositionById(ownerDto.LocationId.Value);
if (!catPosition.Successful)
{
Log.Error("Something went wrong!");
throw new Exception("Something went wrong!");
}
ownerDto.CatPosition = _mapper.Map<CatDto>(catPosition);
}
//------------ Pants
var pants = _ownerRepository.GetPants(ownerDto.Pants);
if (!pants.Successful)
{
Log.Error("log stuff here");
throw new Exception("Something went wrong!");
}
if (Pants == null && !string.IsNullOrEmpty(ownerDto.Pants))
{
pants = _ownerRepository.AddPants(new DbModelPants() { Label = ownerDto.Pants.ToUpper() });
}
if (!pants.Successful)
{
Log.Error("log stuff here");
throw new Exception("Something went wrong!");
}
ownerDto.pantsId = pants.Id;
// Jacket
var jacket = _ownerRepository.GetjacketByLabel(ownerDto.jacket);
if (!jacket.Successful)
{
Log.Error("log stuff here");
throw new Exception("Something went wrong!");
}
if (jacket == null && !string.IsNullOrEmpty(ownerDto.Jacket))
{
jacket = _ownerRepository.Addjacket(new DbModelJacket() { Label = ownerDto.jacket.ToUpper() });
}
if (!jacket.Successful)
{
Log.Error("log stuff here");
throw new Exception("Something went wrong!");
}
ownerDto.JacketId = jacket.Id;
// ------------------------------------
var modelForDatabase = _mapper.Map<OwnerDbModel>(ownerDto);
modelForDatabase.LastModified = DateTime.Now;
var value = _ownerRepository.UpdateOwner(modelForDatabase);
if (!value.Successful)
{
return Result<OwnerDto>.ResultError(value.Error);
}
var returnModel = _mapper.Map<OwnerDto>(value);
// if we move the biscuits we need to create a new owner with the remaining biscuits values that were not moved to the new location
//--------- This adds a new Owner to the db with oldData
if (oldOwner.OldNrOfBiscuits > oldOwner.Biscuits
&& oldOwner.LocationId != oldOwner.LocationId
&& oldOwner.LocationId != null && oldOwner.LocationId != null)
{
oldOwner.Biscuits = oldOwner.OldNrOfBiscuits - oldOwner.Biscuits;
oldOwner.LocationId = oldOwner.LocationId;
oldOwner.Id = 0;
var addedOldSet = AddOwner(oldOwner, PositionEnum.AtThePetStore);
if (!addedOldSet.Successful)
{
Log.Error("log stuff here");
throw new Exception("Something went wrong!");
}
}
return Result<OwnerDto>.ResultOk(returnModel);
}
catch (Exception er)
{
Log.Error("log stuff here");
throw new Exception("Something went wrong!");
}
}
public Result<OwnerDto> AddOwner(OwnerDto owner, PositionEnum catPosition = PositionEnum.InTheGarden)
{
try
{
if (owner.LocationId != null && owner.Status == "AtWork")
{
var catPosition = _catService.GetPositionById(owner.LocationId.Value);
if (!catPosition.Successful)
{
Log.Error("log stuff here");
throw new Exception("Something went wrong!");
}
_catService.UpdatePosition(owner.LocationId.Value, owner.NrBucati, catPosition);
catPosition = _catService.GetPositionById(owner.LocationId.Value);
owner.CatPosition = catPosition;
}
//------------ Pants
// if we don't find the pants with provided name in the table Pants, we add a new set of Pants and provide the Owner with that set. Same for the Jacket.
var pants = _ownerRepository.GetPants(ownerDto.Pants);
if (!pants.Successful)
{
Log.Error("log stuff here");
throw new Exception("Something went wrong!");
}
if (Pants == null && !string.IsNullOrEmpty(ownerDto.Pants))
{
pants = _ownerRepository.AddPants(new DbModelPants() { Label = ownerDto.Pants.ToUpper() });
}
if (!pants.Successful)
{
Log.Error("log stuff here");
throw new Exception("Something went wrong!");
}
ownerDto.PantsId = pants.Id;
//----------- Jacket
var jacket = _ownerRepository.GetjacketByLabel(ownerDto.Jacket);
if (!jacket.Successful)
{
Log.Error("log stuff here");
throw new Exception("Something went wrong!");
}
if (jacket == null && !string.IsNullOrEmpty(ownerDto.Jacket))
{
jacket = _ownerRepository.Addjacket(new DbModelJacket() { Label = ownerDto.jacket.ToUpper() });
}
if (!jacket.Successful)
{
Log.Error("log stuff here");
throw new Exception("Something went wrong!");
}
ownerDto.JacketId = jacket.Id;
var modelForDatabase = _mapper.Map<OwnerDbModel>(owner);
modelForDatabase.LastModified = DateTime.Now;
modelForDatabase.Name = modelForDatabase.Name.ToUpper();
// send model to database
var addedOwner = _ownerRepository.AddOwnerToDatabase(modelForDatabase);
var returnModel = _mapper.Map<OwnerDto>(addedOwner);
return Result<OwnerDto>.ResultOk(returnModel);
}
catch (Exception er)
{
Log.Error("log stuff here");
throw new Exception("Something went wrong!");
}
}
所有存储库内的更新和添加方法都是类似的。
示例:
public Entity UpdateEntity(Entity entityToUpdate)
{
_db.EntityDbSet.Update(entityToUpdate);
_db.SaveChanges();
return entityToUpdate;
}
public Entity AddEntity(Entity entityToAdd)
{
_db.EntityDbSet.Add(entityToAdd);
_db.SaveChanges();
return entityToAdd;
}
问题出在 HTML 文件中。包含模式的部分视图也加载了 js 文件,因此它加载了多次。这就是多个电话的来源。为了使其工作,我在 Index.js 中加载了 js 文件。对于一个疯狂问题的简单解决方案却带来了疯狂的结果......