C# MVC CMS - Настройка удаленной проверки

По ссылке ниже я задал вопрос о том, как убедиться, что поле еще не содержит того же значения (например, когда существует уникальное ограничение для поля, которое правильно заставляет C# генерировать исключение, когда выводится сообщение). Получив ответ, он решил эту проблему, но представил другую.

Обеспечение того, чтобы другая запись еще не содержала того же значения для поля

Основная проблема, с которой я столкнулся, заключается в том, что при создании нового представления. Проверка работает как ожидалось. Вкратце - система должна проверить, что ViewName и ViewPath (маршрут) являются уникальными, поэтому требуется поиск в БД.

Однако, когда я редактирую представление, проверка запускается снова (и на самом деле это не должно происходить, потому что очевидно, что представление уже существует, потому что вы его редактируете).

Теперь моя проблема заключается в том, как настроить удаленную проверку, чтобы она работала по-разному для редактирования и создания. Хотя мы не должны иметь возможности редактировать имя представления в соответствии с существующим представлением, мы также не должны останавливаться на сохранении текущего представления просто потому, что оно совпадает с текущим представлением.

Ниже моя модель (часть, которая (надеюсь) не генерируется инструментом:-):

[MetadataType(typeof(IViewMetaData))]
public partial class View : IViewMetaData { }

public interface IViewMetaData
{
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(DALResources), ErrorMessageResourceName = "ErrorRequiredField")]
    [StringLength(50, ErrorMessageResourceType = typeof(DALResources), ErrorMessageResourceName = "ErrorLessThanCharacters")]
    [Display(ResourceType = typeof(DALResources), Name = "ViewName")]
    [Remote("IsViewNameAvailable", "Validation")]
    string ViewName { get; set; }

    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(DALResources), ErrorMessageResourceName = "ErrorRequiredField")]
    [StringLength(400, ErrorMessageResourceType = typeof(DALResources), ErrorMessageResourceName = "ErrorLessThanCharacters")]
    [Display(ResourceType = typeof(DALResources), Name = "ViewPath")]
    [Remote("IsViewPathAvailable", "Validation")]
    string ViewPath { get; set; }

    [Display(ResourceType = typeof(DALResources), Name = "ViewContent")]
    string ViewContent { get; set; }
}

У меня проблема с атрибутом проверки [Remote], который определен ниже:

[OutputCache(Location = OutputCacheLocation.None, NoStore = true)]
public class ValidationController : Controller
{
    private FRCMSV1Entities db = new FRCMSV1Entities();

    public JsonResult IsViewNameAvailable(View view)
    {
        bool isViewNameInvalid = db.View.Any(v => v.ViewName == view.ViewName && v.Id != view.Id);

        if (!isViewNameInvalid)
            return Json(true, JsonRequestBehavior.AllowGet);

        string suggestedViewName = string.Format(UI_Prototype_MVC_Resources.ErrorViewAlreadyExists, view.ViewName);

        for (int i = 1; i < 100; i++)
        {
            string altViewName = view.ViewName + i.ToString();
            bool doesAltViewNameExist = db.View.Any(v => v.ViewName == altViewName);
            if (!doesAltViewNameExist)
            {
                suggestedViewName = string.Format(UI_Prototype_MVC_Resources.ErrorViewNotAvailableTry, view.ViewName, altViewName);
                break;
            }
        }
        return Json(suggestedViewName, JsonRequestBehavior.AllowGet);
    }

    public JsonResult IsViewPathAvailable(View view)
    {
        bool doesViewPathExist = db.View.Any(v => v.ViewPath == view.ViewPath && v.Id != view.Id);

        if (!doesViewPathExist)
            return Json(true, JsonRequestBehavior.AllowGet);

        string suggestedViewPath = string.Format(UI_Prototype_MVC_Resources.ErrorViewAlreadyExists, view.ViewPath);

        for (int i = 1; i < 100; i++)
        {
            string altViewPath = view.ViewPath + i.ToString();
            bool doesAltViewPathExist = db.View.Any(v => v.ViewPath == altViewPath);
            if (!doesAltViewPathExist)
            {
                suggestedViewPath = string.Format(UI_Prototype_MVC_Resources.ErrorViewNotAvailableTry, view.ViewPath, altViewPath);
                break;
            }
        }
        return Json(suggestedViewPath, JsonRequestBehavior.AllowGet);
    }
}

Проблема в том, что проверка должна работать одинаково как при создании, так и при редактировании. Просто нужно выполнить дополнительную проверку редактирования, чтобы убедиться, что мы все еще ссылаемся на ту же запись, и если это так, то нет необходимости показывать сообщение проверки, потому что в этом нет ничего плохого.

Мой вопрос: 1. Как мне заставить это работать как ожидалось. 2. Я вижу, что оба метода в значительной степени идентичны, что нарушает принцип СУХОГО. Как я могу сделать это более общим и упростить это. Однако на первый вопрос я действительно хотел бы ответить, потому что нет смысла рефакторинг чего-то, что не работает.

Для получения дополнительной информации вышеуказанный код также является редактированием кода по следующей ссылке:

https://msdn.microsoft.com/en-us/library/gg508808(VS.98).aspx

Спасибо за любую помощь.

1 ответ

Решение

Вам нужно добавить параметр, чтобы передать свойство ID модели как AdditionalFields, Предполагая его int Id, затем

[Remote("IsViewPathAvailable", "Validation", AdditionalFields = "Id")]
public string ViewName { get; set; }

и метод должен быть

public JsonResult IsViewNameAvailable(string viewName, int? id)

Обратите внимание, что в Edit вид, вы включаете скрытый вход для Id свойство, поэтому его значение будет отправлено обратно удаленной функцией jquery.validate.

Затем вы можете проверить, если id параметр null (то есть он новый) или имеет значение (он существует) и корректирует запросы в соответствии с требованиями.

bool isViewNameInvalid;
if (id.HasValue)
{
    isViewNameInvalid = db.View.Any(v => v.ViewName == viewName && v.Id != id);
}
else
{
    isViewNameInvalid = db.View.Any(v => v.ViewName == ViewName);
}

В настоящее время происходит то, что Remote только публикует значение ViewName свойство, а так как ваш параметр является моделью, он инициализируется со значением по умолчанию id значение (0) и ваш запрос переведен на Any(v => v.ViewName == viewName && v.Id != 0);

Я также рекомендую использовать модель вида, а не partial class

Примечание: из кода, который генерирует suggestedViewName, вы ожидаете много ViewName с тем же значением, означающим, что вы, возможно, делаете многочисленные обращения к базе данных внутри вас for петля. Вы можете рассмотреть возможность использования linq .StartsWith() запрос, чтобы получить все записи, которые начинаются с вашего ViewName значение, а затем проверьте набор в памяти в вашем цикле.

Другие вопросы по тегам