【问题标题】:MVC5 Controller: Check for duplicate in DB before saving?MVC5 控制器:保存前检查数据库中的重复项?
【发布时间】:2015-03-12 16:12:12
【问题描述】:

在我的View 上,我有一个按钮,用于通过 JSON 向我的Controller 提交[description] 值,然后用于创建新的Table 记录。例如:

    [HttpPost]
    public JsonResult createNewStatus(string description)
    {
        INV_Statuses status = new INV_Statuses()
        {
            // ID auto-set during save
            status_description = description,
            created_date = DateTime.Now,
            created_by = System.Environment.UserName
        };

        //var allErrors = ModelState.Values.SelectMany(x => x.Errors);

        try
        {
            if (ModelState.IsValid)
            {
                db.INV_Statuses.Add(status);
                db.SaveChanges();
            }

        }
        catch (Exception ex)
        {
            Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
        }

        return Json(new { ID = status.Id, Text = status.status_description }, JsonRequestBehavior.AllowGet);
    }

我现在想做的是(在将状态保存到数据库之前)运行检查以查看INV_Statuses 表中的任何其他记录是否具有与提交给函数的[description] 值匹配的值新的创造。如果匹配,我想返回一个error/validation? 消息并提醒用户提交的值已经存在,并从视图上的DropDownList 中选择它。

谁能提供一个如何在我的 MVC 控制器中使用 LINQ 的示例?


编辑:添加了我的View JS 代码以提交新状态:

        $('#createNewStatus').click(function () {
            $('#createStatusFormContainer').show();
        })

        $('#cancelNewStatus').click(function () {
            $('#createStatusFormContainer').hide();
        })

        $('#submitNewStatus').click(function () {
            var form = $(this).closest('form');
            var data = { description: document.getElementById('textNewStatus').value };

            $.ajax({
                type: "POST",
                dataType: "JSON",
                url: '@Url.Action("createNewStatus", "INV_Assets")',
                data: data,
                success: function (resp) {
                    $('#selectStatus').append($('<option></option>').val(resp.ID).text(resp.Text));
                    form[0].reset();
                    $('#createStatusFormContainer').hide();
                    var count = $('#selectStatus option').size();
                    $("#selectStatus").prop('selectedIndex', count - 1);
                },
                error: function () {
                    alert("ERROR!");
                }
            });
        });

EDIT2

Adricadar 的建议:

        INV_Statuses status = new INV_Statuses()
        {
            // ID auto-set during save
            status_description = description,
            created_date = DateTime.Now,
            created_by = System.Environment.UserName
        };

        try
        {
            var existingStatus = db.INV_Statuses.FirstOrDefault(x => x.status_description.ToUpper() == status.status_description.ToUpper());
            var isDuplicateDescription = existingStatus != null;

            if (isDuplicateDescription)
            {
                ModelState.AddModelError("Error", "[" + status.status_description + "] already exists in the database. Please select from the DropDownList.");
            }
            else if (ModelState.IsValid)
            {
                db.INV_Statuses.Add(status);
                db.SaveChanges();
            }
        }
        catch (Exception ex)
        {
            Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
        }

        return Json(new { ID = status.Id, Text = status.status_description }, JsonRequestBehavior.AllowGet);

我在 Controller 中的比较中添加了 .ToUpper(),但即使识别出与 .ToUpper() 的匹配项,ModelState.AddModelError() 代码也会触发,然后代码返回并且没有发出错误消息?

值(虽然重复)仍然通过我当前的 JS 代码添加到下拉列表中(视觉上,不在 DB 中):

        $('#createNewStatus').click(function () {
            $('#createStatusFormContainer').show();
        })

        $('#cancelNewStatus').click(function () {
            $('#createStatusFormContainer').hide();
        })

        $('#submitNewStatus').click(function () {
            var form = $(this).closest('form');
            var data = { description: document.getElementById('textNewStatus').value };

            $.ajax({
                type: "POST",
                dataType: "JSON",
                url: '@Url.Action("createNewStatus", "INV_Assets")',
                data: data,
                success: function (resp) {
                    $('#selectStatus').append($('<option></option>').val(resp.ID).text(resp.Text));
                    form[0].reset();
                    $('#createStatusFormContainer').hide();
                    var count = $('#selectStatus option').size();
                    $("#selectStatus").prop('selectedIndex', count - 1);
                },
                error: function () {
                    alert("ERROR!");
                }
            });
        });

【问题讨论】:

  • 听起来您需要在表上添加唯一约束,并在尝试插入时捕获结果错误。或者您需要先查找它,但我坚信数据库会强制执行它可以执行的操作,因为尝试使用该表的下一个应用程序可能会尝试插入重复项。
  • @RobertMcKee,这是个好主意。关于如何在我的表字段(例如)[status_description] 上实现唯一约束的任何想法?我目前正在通过 Code-First 开发使用本地 DbMigrationsConfiguration&lt;InventoryTracker.DAL.InventoryTrackerContext&gt;,但在 PROD 中将引用 ORACLE 中的表。
  • 对不起,你得问别人,我总是先做数据库。

标签: c# json asp.net-mvc linq controller


【解决方案1】:

检查现有状态并将状态设置回如下:

var existingStatus = db.INV_Statuses.FirstOrDefault(s => s.status_description == description);

if (existingStatus ==null)
{
   db.INV_Statuses.Add(status);
   db.SaveChanges();
}
else 
{ 
   // set the status back to existing
   status = existingStatus;   
}

在您的响应中设置现有标志:

return Json(new { ID = status.Id, Text = status.status_description, AlreadyExists = (existingStatus != null)  }, JsonRequestBehavior.AllowGet);

然后在你的响应 JavaScript 中,简单地解析出返回的数据:

success: function (resp) {

if (resp.AlreadyExists != true)
{
     $('#selectStatus').append($('<option></option>').val(resp.ID).text(resp.Text));
     form[0].reset();
     $('#createStatusFormContainer').hide();
     var count = $('#selectStatus option').size();
     $("#selectStatus").prop('selectedIndex', count - 1);
      }
      else
      {
         alert(resp.status_description + " already exists");
         $("#selectStatus").val(resp.Id);
      }
 }

【讨论】:

  • 谢谢,我会试一试。我认为您的 return Json 段中有错字/缺少右括号,但我不太确定在哪里。
  • @AnalyticLunatic 对不起,我现在看到错字了,可能还有更多,因为浏览器窗口中没有编译器。 :)
  • 嗯...我有点困惑如何最好地构造控制器中的代码以及您建议的添加内容?目前我检查了existingStatus 变量,如果null/Model.IsValid 我保存状态。 Else 我设置了status = existingStatus 然后返回。鉴于我的视图上的 JSON 返回与resp 检查success/error,我将如何处理返回? (在编辑中添加)。我想我只是对在返回视图时 existingStatussuccess/error 的关系如何使用感到困惑?
【解决方案2】:

您可以在数据库中查询具有现有描述的状态以及是否存在以及模型状态错误。

请注意,字符串比较区分大小写

[HttpPost]
public JsonResult createNewStatus(string description)
{
    INV_Statuses status = new INV_Statuses()
    {
        // ID auto-set during save
        status_description = description,
        created_date = DateTime.Now,
        created_by = System.Environment.UserName
    };

    //var allErrors = ModelState.Values.SelectMany(x => x.Errors);

    try
    {
        var existingStatus = db.INV_Statuses.FirstOrDefault(x => x.status_description.ToUpper() == status.status_description.ToUpper());
        var isDuplicateDescription = existingStatus != null;

        string error = String.Empty;
        if (isDuplicateDescription)
        {
           error = "[" + status.status_description + "] already exists in the database. Please select from the DropDownList.";
        }
        else if (ModelState.IsValid)
        {
            db.INV_Statuses.Add(status);
            db.SaveChanges();
        }

    }
    catch (Exception ex)
    {
        Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
    }

    return Json(new { ID = status.Id, Text = status.status_description, Error = error , IsDuplicate = isDuplicateDescription }, JsonRequestBehavior.AllowGet);
}

javascript 中验证响应是否有IsDuplicate = true 如果为真,则跳过需要在下拉列表中添加元素的部分。

    $('#createNewStatus').click(function () {
        $('#createStatusFormContainer').show();
    })

    $('#cancelNewStatus').click(function () {
        $('#createStatusFormContainer').hide();
    })

    $('#submitNewStatus').click(function () {
        var form = $(this).closest('form');
        var data = { description: document.getElementById('textNewStatus').value };

        $.ajax({
            type: "POST",
            dataType: "JSON",
            url: '@Url.Action("createNewStatus", "INV_Assets")',
            data: data,
            success: function (resp) {
                if(resp.IsDuplicate)
                {
                     //display error from response
                     //display resp.Error
                } else {
                    $('#selectStatus').append($('<option></option>').val(resp.ID).text(resp.Text));
                    form[0].reset();
                    $('#createStatusFormContainer').hide();
                    var count = $('#selectStatus option').size();
                    $("#selectStatus").prop('selectedIndex', count - 1);
                }
            },
            error: function () {
                alert("ERROR!");
            }
        });
    });

【讨论】:

  • 谢谢阿德里卡达尔。我尝试了您的建议,但遇到了一些奇怪的行为。请参阅我的 EDIT2。
  • @AnalyticLunatic 我看到了您的编辑 2,您在下拉列表中看到重复记录,因为您没有签入 javascript 以查看它是否是重复的描述。查看我编辑的C# 代码和Javascript
猜你喜欢
  • 2014-10-12
  • 2012-11-23
  • 1970-01-01
  • 2015-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多