Ошибка метаданных в узле [duplicate]

Ошибка означает, что значение CategoryList равно нулю (и в результате метод DropDownListFor() ожидает, что первый параметр имеет тип IEnumerable).

Вы не генерируете вход для каждого свойства каждого SelectListItem в CategoryList (и не должен), поэтому никакие значения для SelectList не отправляются в метод контроллера, и поэтому значение model.CategoryList в методе POST равно null , Если вы вернете представление, вы должны сначала переназначить значение CategoryList, как и в методе GET.

public ActionResult Create(ProjectVM model)
{
    if (!ModelState.IsValid)
    {
        model.CategoryList = new SelectList(db.Categories, "ID", "Name"); // add this
        return View(model);
    }
    // Save and redirect
}

Чтобы объяснить внутреннюю работу (исходный код может быть см. здесь )

Каждая перегрузка DropDownList() и DropDownListFor() в конечном итоге вызывает следующий метод

private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, ModelMetadata metadata,
  string optionLabel, string name, IEnumerable selectList, bool allowMultiple,
  IDictionary htmlAttributes)

, который проверяет, есть ли selectList (второй параметр из @Html.DropDownListFor()) является null

// If we got a null selectList, try to use ViewData to get the list of items.
if (selectList == null)
{
    selectList = htmlHelper.GetSelectData(name);
    usedViewData = true;
}

, который, в свою очередь, вызывает

private static IEnumerable GetSelectData(this HtmlHelper htmlHelper, string name)

, который оценивает первый параметр @Html.DropDownListFor() (в данном случае CategoryID )

....
o = htmlHelper.ViewData.Eval(name);
....
IEnumerable selectList = o as IEnumerable;
if (selectList == null)
{
    throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, 
        MvcResources.HtmlHelper_WrongSelectDataType,
        name, o.GetType().FullName, "IEnumerable"));
}

Поскольку свойство CategoryID является typeof int, оно не может быть передано в IEnumerable, и генерируется исключение (которое определено в файле MvcResources.resx как)


    The ViewData item that has the key '{0}' is of type '{1}' but must be of type '{2}'.

144
задан mmierins 20 March 2011 в 09:02
поделиться

8 ответов

ECMAScript 2018 вводит группы захвата в регулярные выражения JavaScript.

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

Есть только два «структурных» преимущества названных групп захвата, о которых я могу думать:

  1. В некоторых вариантах регулярных выражений (.NET и JGSoft, насколько я знаю) , вы можете использовать одно и то же имя для разных групп в вашем регулярном выражении ( см. здесь для примера, где это имеет значение ). Но большинство разновидностей регулярных выражений в любом случае не поддерживают эту функциональность.
  2. Если вам нужно сослаться на нумерованные группы захвата в ситуации, когда они окружены цифрами, вы можете получить проблему. Предположим, вы хотите добавить нуль к цифре и, следовательно, хотите заменить (\d) на $10. В JavaScript это будет работать (пока у вас будет менее 10 групп захвата в вашем регулярном выражении), но Perl подумает, что вы ищете номер обратной ссылки 10 вместо номера 1, а затем 0. В Perl вы можете использовать ${1}0 в этом случае.

Кроме этого, группы захвата называются «синтаксическим сахаром». Это помогает использовать группы захвата только тогда, когда они вам действительно нужны, и использовать не захватывающие группы (?:...) во всех других обстоятельствах.

Большая проблема (на мой взгляд) с JavaScript заключается в том, что она не поддерживает многословные регулярные выражения, которые значительно упростили бы создание понятных и сложных регулярных выражений.

Библиотека XRegExp Стив Левитана решает эти проблемы.

65
ответ дан Tim Pietzcker 19 August 2018 в 07:08
поделиться
  • 1
    Многие варианты позволяют использовать одно и то же имя группы захвата несколько раз в регулярном выражении. Но только .NET и Perl 5.10+ делают это особенно полезным, сохраняя значение, захваченное последней группой имени, которое участвовало в матче. – slevithan 1 June 2012 в 04:36
  • 2
    Огромное преимущество: вы можете просто изменить свой RegExp, не сопоставляя число-переменные. Нехватывающие группы решают эту проблему, за исключением одного случая: что, если порядок групп изменяется? Кроме того, это аннонируется, чтобы поместить эти дополнительные символы в другие группы ... – Alba Mendez 9 November 2012 в 17:45
  • 3
    Так называемый синтаксический сахар делает помогает подсластить читаемость кода! – Mrchief 31 July 2013 в 19:32
  • 4
    Он будет заполнять непревзойденные с неопределенным. Некоторые языки не заставят вас использовать именованные. – jgmjgm 10 September 2015 в 01:37
  • 5
    Я думаю, что есть еще одна причина для названных групп захвата, которые действительно ценны. Например, если вы хотите использовать регулярное выражение для синтаксического анализа даты из строки, вы можете написать гибкую функцию, которая принимает значение и регулярное выражение. Пока регулярное выражение назвало захваты за год, месяц и дату, вы можете запустить массив регулярных выражений с минимальным кодом. – Dewey Vozel 18 January 2016 в 21:33

Вы можете использовать XRegExp , расширенную, расширяемую кросс-браузерную реализацию регулярных выражений, включая поддержку дополнительного синтаксиса, флагов и методов:

  • Добавляет новый синтаксис регулярных выражений и замены текста, включая всестороннюю поддержку с именем capture .
  • Добавляет два новых флага регулярных выражений: s, чтобы совместить точки со всеми символами (так называемый dotall или singleline mode ) и x, для свободного пробела и комментариев (aka extended mode).
  • Предоставляет набор функций и методов, которые делают сложный регулярный анализ обработанным.
  • Автоматически исправляет наиболее часто встречающиеся непоследовательности кросс-браузера в поведении и синтаксисе regex.
  • Позволяет вам легко создавать и использовать плагины, которые добавляют новый синтаксис и флаги к регулярному языку выражения XRegExp.
60
ответ дан Barett 19 August 2018 в 07:08
поделиться

В ES6 вы можете использовать деструктурирование массива для захвата ваших групп:

let text = '27 months';
let regex = /(\d+)\s*(days?|months?|years?)/;
let [, count, unit] = text.match(regex) || [];

// count === '27'
// unit === 'months'

Примечание:

  • первая запятая в последнем let пропускает первое значение результирующего массива, который представляет собой всю согласованную строку
  • , || [] после .match() предотвратит ошибку разрушения, если совпадений нет (поскольку .match() вернет null)
38
ответ дан bfred.it 19 August 2018 в 07:08
поделиться
  • 1
    Первая запятая состоит в том, что первый элемент массива, возвращаемый совпадением, является входным выражением, правильно? – Emilio Grisolía 31 July 2016 в 01:04
  • 2
    String.prototype.match возвращает массив с: всей согласованной строкой в ​​позиции 0, затем после каждой группы. Первая запятая говорит «пропустить элемент в положении 0», – bfred.it 31 July 2016 в 06:34
  • 3
    Мой любимый ответ здесь для тех, у кого есть транспиляция или цели ES6 +. Это не обязательно предотвращает ошибки несоответствия, а также именованные индексы, если, например, повторно используется регулярное выражение, но я думаю, что краткость здесь легко компенсирует это. Я выбрал RegExp.prototype.exec над String.prototype.match в местах, где строка может быть null или undefined. – Mike Hill 31 July 2017 в 15:29

Существует библиотека node.js, названная named-regexp , которую вы можете использовать в проектах node.js (в браузере, упаковывая библиотеку с помощью браузера или других сценариев упаковки). Тем не менее, библиотека не может использоваться с регулярными выражениями, которые содержат неименованные группы захвата.

Если вы считаете открывающие скобки для захвата в своем регулярном выражении, вы можете создать сопоставление между именованными группами захвата и пронумерованными группами захвата в вашем регулярном выражении и может свободно смешиваться и сочетаться. Вам просто нужно удалить имена групп, прежде чем использовать регулярное выражение. Я написал три функции, которые демонстрируют это. См. Этот пункт: https://gist.github.com/gbirke/2cc2370135b665eee3ef

5
ответ дан chiborg 19 August 2018 в 07:08
поделиться
  • 1
    Это удивительно легкий, я попробую – bfred.it 1 August 2016 в 05:58
  • 2
    Работает ли она с вложенными именованными группами внутри регулярных групп в сложных регулярных выражениях? – ElSajko 14 October 2016 в 22:18
  • 3
    Это не идеально. Ошибка, когда: getMap (& quot; ((a | b (: & lt; foo & gt; c))) "); foo должен быть третьей, а не второй. /((a|b(c)))/g.exec("bc"); [& quot; bc "," bc "," bc "," c "], – ElSajko 14 October 2016 в 22:27

Именованные группы захвата могут быстро перейти на JavaScript. Предложение для него уже на этапе 3.

Группе захвата может быть присвоено имя с использованием синтаксиса (? ...) для любого имени идентификатора. Регулярное выражение для даты тогда может быть записано как / (? \ D {4}) - (? \ D {2}) - (? \ D {2}) / u. Каждое имя должно быть уникальным и следовать грамматике для имени идентификатора ECMAScript.

Именованные группы могут быть доступны из свойств свойства групп результата регулярного выражения. Также создаются нумерованные ссылки на группы, как и для неименованных групп. Например:

let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
let result = re.exec('2015-01-02');
// result.groups.year === '2015';
// result.groups.month === '01';
// result.groups.day === '02';

// result[0] === '2015-01-02';
// result[1] === '2015';
// result[2] === '01';
// result[3] === '02';
3
ответ дан Forivin 19 August 2018 в 07:08
поделиться

Хотя вы не можете сделать это с помощью ванильного JavaScript, возможно, вы можете использовать некоторую функцию Array.prototype, например Array.prototype.reduce, чтобы превратить индексированные совпадения в именованные, используя некоторую магию .

Очевидно, что следующее решение потребует, чтобы совпадения выполнялись по порядку:

// @text Contains the text to match
// @regex A regular expression object (f.e. /.+/)
// @matchNames An array of literal strings where each item
//             is the name of each group
function namedRegexMatch(text, regex, matchNames) {
  var matches = regex.exec(text);

  return matches.reduce(function(result, match, index) {
    if (index > 0)
      // This substraction is required because we count 
      // match indexes from 1, because 0 is the entire matched string
      result[matchNames[index - 1]] = match;

    return result;
  }, {});
}

var myString = "Hello Alex, I am John";

var namedMatches = namedRegexMatch(
  myString,
  /Hello ([a-z]+), I am ([a-z]+)/i, 
  ["firstPersonName", "secondPersonName"]
);

alert(JSON.stringify(namedMatches));

2
ответ дан Matías Fidemraizer 19 August 2018 в 07:08
поделиться
  • 1
    Это круто. Я просто думаю .. не было бы возможно создать функцию регулярного выражения, которая принимает пользовательское регулярное выражение? Чтобы вы могли пойти как var assocArray = Regex("hello alex, I am dennis", "hello ({hisName}.+), I am ({yourName}.+)"); – Forivin 29 August 2015 в 16:46
  • 2
    @Forivin Ясно, что вы можете пойти дальше и развить эту функцию. Нетрудно заставить его работать: D – Matías Fidemraizer 29 August 2015 в 19:38
  • 3
    Вы можете расширить объект RegExp, добавив функцию в свой прототип. – Mr. TA 16 February 2016 в 20:27
  • 4
    @ Mr.TA AFAIK, не рекомендуется расширять встроенные объекты – Matías Fidemraizer 16 February 2016 в 20:50
  • 5
    @ MatíasFidemraizer Tampoco hay que ser extremistas che ... – Emilio Grisolía 31 July 2016 в 01:36

Другое возможное решение: создать объект, содержащий имена групп и индексы.

var regex = new RegExp("(.*) (.*)");
var regexGroups = { FirstName: 1, LastName: 2 };

Затем используйте клавиши объектов для ссылки на группы:

var m = regex.exec("John Smith");
var f = m[regexGroups.FirstName];

Это улучшает читаемость / качество кода с использованием результатов регулярного выражения, но не читаемость самого регулярного выражения.

47
ответ дан Mr. TA 19 August 2018 в 07:08
поделиться

Именование захваченных групп дает одну вещь: меньше путаницы со сложными регулярными выражениями.

Это действительно зависит от вашего прецедента, но, может быть, довольно-печатать ваше регулярное выражение может помочь.

Или вы можете попытаться определить константы для ссылки на ваши захваченные группы.

Комментарии могут также помочь показать другим, кто читает ваш код, что вы сделали.

В остальном я должен согласиться с ответом Тимов.

6
ответ дан Yashima 19 August 2018 в 07:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: