Как увеличить значение поля в массиве с помощью mongodb C # driver [duplicate]

Что такое NullPointerException?

Хорошим местом для начала является JavaDocs . Они охватывают это:

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

  • Вызов метода экземпляра нулевого объекта.
  • Доступ или изменение поля нулевого объекта.
  • Выполнение длины null, как если бы это был массив.
  • Доступ или изменение слотов с нулевым значением, как если бы это был массив.
  • Бросать нуль, как если бы это было значение Throwable.

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

blockquote>

Также, если вы попытаетесь использовать нулевую ссылку с synchronized, который также выдаст это исключение, за JLS :

SynchronizedStatement:
    synchronized ( Expression ) Block
  • В противном случае, если значение выражения равно null, NullPointerException.
blockquote>

Как это исправить?

Итак, у вас есть NullPointerException. Как вы это исправите? Возьмем простой пример, который выдает NullPointerException:

public class Printer {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }
}

Идентифицирует нулевые значения

. Первый шаг - точно определить , значения которого вызывают исключение . Для этого нам нужно выполнить некоторую отладку. Важно научиться читать stacktrace . Это покажет вам, где было выбрано исключение:

Exception in thread "main" java.lang.NullPointerException
    at Printer.printString(Printer.java:13)
    at Printer.print(Printer.java:9)
    at Printer.main(Printer.java:19)

Здесь мы видим, что исключение выбрано в строке 13 (в методе printString). Посмотрите на строку и проверьте, какие значения равны нулю, добавив протоколирующие операторы или используя отладчик . Мы обнаруживаем, что s имеет значение null, а вызов метода length на него вызывает исключение. Мы видим, что программа перестает бросать исключение, когда s.length() удаляется из метода.

Трассировка, где эти значения взяты из

Затем проверьте, откуда это значение. Следуя вызовам метода, мы видим, что s передается с printString(name) в методе print(), а this.name - null.

Трассировка, где эти значения должны быть установлены

Где установлен this.name? В методе setName(String). С некоторой дополнительной отладкой мы видим, что этот метод вообще не вызывается. Если этот метод был вызван, обязательно проверьте порядок , что эти методы вызывают, а метод set не будет называться после методом печати. ​​

Этого достаточно, чтобы дать нам решение: добавить вызов printer.setName() перед вызовом printer.print().

Другие исправления

Переменная может иметь значение по умолчанию setName может помешать ему установить значение null):

private String name = "";

Либо метод print, либо printString может проверить значение null например:

printString((name == null) ? "" : name);

Или вы можете создать класс, чтобы name всегда имел ненулевое значение :

public class Printer {
    private final String name;

    public Printer(String name) {
        this.name = Objects.requireNonNull(name);
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer("123");
        printer.print();
    }
}

См. также:

Я все еще не могу найти проблему

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

11
задан Kristian Barrett 16 July 2015 в 12:14
поделиться

3 ответа

Понадобилось время, чтобы понять это, поскольку оно, похоже, не упоминается ни в одной официальной документации (или где-либо еще). Тем не менее, я нашел этот в своем трекере проблем, в котором объясняется, как использовать оператор позиционирования $ с драйвером C # 2.0.

Это должно делать то, что вы хотите:

public void UpdateItemTitle(string agendaId, string itemId, string title){
    var filter = Builders<TempAgenda>.Filter.Where(x => x.AgendaId == agendaId && x.Items.Any(i => i.Id == itemId));
    var update = Builders<TempAgenda>.Update.Set(x => x.Items[-1].Title, title);
    var result = _collection.UpdateOneAsync(filter, update).Result;
}

Обратите внимание, что ваше предложение Item.Single() было изменено на Item.Any() и перешло в определение фильтра.

[-1] или .ElementAt(-1), по-видимому, обрабатывается специально (на самом деле все & lt; 0) и будет заменен позиционным оператором $.

Вышеупомянутое будет переведено на этот запрос:

db.Agenda.update({ AgendaId: 1, Items.Id: 1 }, { $set: { Items.$.Title: "hello" } })
34
ответ дан Søren Kruse 18 August 2018 в 21:11
поделиться
  • 1
    Извините за то, что вы так медленно принимаете свой ответ. Работает очень хорошо. К сожалению, они не поддерживают более одного операционного селектора: jira.mongodb.org/browse/SERVER-831 Мне кажется странным, поскольку это можно использовать для лучшей изоляции обновления, необходимого для сделайте. – Kristian Barrett 21 September 2016 в 14:29
  • 2
    Спасибо Søren. Я должен сказать, что я не поклонник синтаксиса, который они выбрали, потому что это означает, что вы не можете использовать IEnumerable & lt; T & gt; или ICollection & lt; T & gt; и заставляет вас использовать более громоздкий IList & lt; T & gt; или простой массив – Buvy 2 November 2016 в 00:31
  • 3
    @Buvy Вы также должны использовать метод расширения LINQ ElementAt(-1). – Søren Kruse 2 November 2016 в 11:02
  • 4
    @ SørenKruse, вы действительно правы, в то время как этот синтаксис, который я только что проверил, работает как шарм. это немного громоздко по сравнению с индексом массива, но по крайней мере мне не нужно, чтобы все мои классы домена использовали IList & lt; T & gt; это то, чем я был. – Buvy 2 November 2016 в 19:14

Спасибо, это было полезно. У меня есть дополнение, хотя, я использовал выше для массивов, нажав на вложенный массив и вытащив из него. Проблема, которую я обнаружил, заключается в том, что если бы у меня был массив int (а не объект, просто простой массив int), который PullFilter фактически не работал - «Невозможно определить информацию о сериализации», что странно, поскольку это всего лишь массив of ints. То, что я закончил, делало его массивом объектов только с одним параметром int, и все это начало работать. Возможно, ошибка, или, может быть, мое отсутствие понимания. Во всяком случае, поскольку я изо всех сил пытался найти информацию о том, как вытащить и нажав на вложенные массивы объектов с помощью драйвера C # 2.0, мне показалось, что я должен опубликовать свои результаты здесь, поскольку они используют вышеупомянутый синтаксис.

var filter = Builders<MessageDto>.Filter.Where(x => x._id == entity.ParentID && x.NestedArray.Any(i => i._id == entity._id));
var update = Builders<MessageDto>.Update.PullFilter(x => x.NestedArray.ElementAt(-1).User, Builders<User>.Filter.Eq(f => f.UserID, userID));
Collection<MessageDto>(currentUser).UpdateOneAsync(filter, update);

А также:

var filter = Builders<MessageDto>.Filter.Where(x => x._id == entity.ParentID && x.NestedArray.Any(i => i._id == entity._id));
var update = Builders<MessageDto>.Update.Push(x => x.NestedArray.ElementAt(-1).Users, new User { UserID = userID });
Collection<MessageDto>(currentUser).UpdateOneAsync(filter, update);
1
ответ дан davoc bradley 18 August 2018 в 21:11
поделиться

Правильный способ обновления документа или вспомогательного массива выглядит следующим образом:

var filter = Builders<Declaracion>.Filter.Where(x => x.Id == di && x.RemuneracionMensualActual.RemuneracionActIndustrial.Any(s => s.Id == oid));

        var update = Builders<Declaracion>.Update.Set(x => x.RemuneracionMensualActual.RemuneracionActIndustrial.ElementAt(-1).Ingreso, datos.ActividadIndustrial.Ingreso)
            .Set(x => x.RemuneracionMensualActual.RemuneracionActIndustrial.ElementAt(-1).RazonSocial, datos.ActividadIndustrial.RazonSocial)
            .Set(x => x.RemuneracionMensualActual.RemuneracionActIndustrial.ElementAt(-1).TipoNegocio, datos.ActividadIndustrial.TipoNegocio);
-1
ответ дан Patrick 18 August 2018 в 21:11
поделиться
Другие вопросы по тегам:

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