Каждый раз, когда вы получаете ...
"Warning: mysqli_fetch_object () ожидает, что параметр 1 будет mysqli_result, boolean задан«
blockquote>... это, вероятно, из-за проблемы с вашим запросом.
prepare()
илиquery()
могут возвращатьFALSE
(логическое), но это общее сообщение об отказе не оставляет вас в стороне от подсказок. Как вы узнаете, что не так с вашим запросом? Вы задаете !Прежде всего убедитесь, что сообщения об ошибках включены и видны: добавьте эти две строки в начало файла (ов) сразу после открытия
<?php
:error_reporting(E_ALL); ini_set('display_errors', 1);
Если ваше сообщение об ошибках установлено в php.ini, вам не придется беспокоиться об этом. Просто убедитесь, что вы обрабатываете ошибки изящно и никогда не раскрываете истинные причины каких-либо проблем для ваших пользователей. Выявление истинной причины для общественности может быть приглашением на золото с гравировкой для тех, кто хочет нанести вред вашим сайтам и серверам. Если вы не хотите отправлять ошибки в браузер, вы всегда можете следить за журналами ошибок веб-сервера. Расположение журналов будет варьироваться от сервера к серверу, например, на Ubuntu журнал ошибок обычно находится в
/var/log/apache2/error.log
. Если вы изучаете журналы ошибок в среде Linux, вы можете использоватьtail -f /path/to/log
в окне консоли, чтобы видеть ошибки, когда они происходят в режиме реального времени .... или как вы их делаете.Как только вы 'squared away на стандартном сообщении об ошибках, добавляющем проверку ошибок в вашем соединении с базой данных, и запросы дадут вам гораздо более подробную информацию о проблемах. Посмотрите на этот пример, где имя столбца неверно. Во-первых, код, возвращающий роковое сообщение об ошибке:
$sql = "SELECT `foo` FROM `weird_words` WHERE `definition` = ?"; $query = $mysqli->prepare($sql)); // assuming $mysqli is the connection $query->bind_param('s', $definition); $query->execute();
Ошибка является общей и не очень помогает вам в решении того, что происходит.
С помощью пары больше строк кода вы можете получить очень подробную информацию, которую вы можете использовать для решения проблемы сразу . Проверьте утверждение
prepare()
для правдивости, и если это хорошо, вы можете перейти к привязке и исполнению.$sql = "SELECT `foo` FROM `weird_words` WHERE `definition` = ?"; if($query = $mysqli->prepare($sql)) { // assuming $mysqli is the connection $query->bind_param('s', $definition); $query->execute(); // any additional code you need would go here. } else { $error = $mysqli->errno . ' ' . $mysqli->error; echo $error; // 1054 Unknown column 'foo' in 'field list' }
Если что-то не так, вы можете выплюнуть сообщение об ошибке, которое приведет вас к проблеме , В этом случае в таблице нет столбца
foo
, решение проблемы тривиально.Если вы выберете, вы можете включить эту проверку в функцию или класс и расширить ее, обработав ошибки изящно, как упомянутых ранее.
Этого не существует, но вы можете быстро построить его из словаря и списка:
class MultiDict<TKey, TValue> // no (collection) base class
{
private Dictionary<TKey, List<TValue>> _data = new Dictionary<TKey,List<TValue>>();
public void Add(TKey k, TValue v)
{
// can be a optimized a little with TryGetValue, this is for clarity
if (_data.ContainsKey(k))
_data[k].Add(v)
else
_data.Add(k, new List<TValue>() { v}) ;
}
// more members
}
Просто добавьте мои $ 0.02 в коллекцию решений:
У меня была такая же потребность еще в 2011 году и была создана MultiDictionary
с педантично полной реализацией всех интерфейсов .NET. Это включает перечисления, которые возвращают стандарт KeyValuePair<K, T>
и поддерживают свойство IDictionary<K, T>.Values
, предоставляя набор фактических значений (вместо ICollection<ICollection<T>>
).
Таким образом, он вписывается аккуратно с остальными классов коллекции .NET. Я также определил интерфейс IMultiDictionary<K, T>
для доступа к операциям, которые относятся к этому типу словаря:
public interface IMultiDictionary<TKey, TValue> :
IDictionary<TKey, ICollection<TValue>>,
IDictionary,
ICollection<KeyValuePair<TKey, TValue>>,
IEnumerable<KeyValuePair<TKey, TValue>>,
IEnumerable {
/// <summary>Adds a value into the dictionary</summary>
/// <param name="key">Key the value will be stored under</param>
/// <param name="value">Value that will be stored under the key</param>
void Add(TKey key, TValue value);
/// <summary>Determines the number of values stored under a key</summary>
/// <param name="key">Key whose values will be counted</param>
/// <returns>The number of values stored under the specified key</returns>
int CountValues(TKey key);
/// <summary>
/// Removes the item with the specified key and value from the dictionary
/// </summary>
/// <param name="key">Key of the item that will be removed</param>
/// <param name="value">Value of the item that will be removed</param>
/// <returns>True if the item was found and removed</returns>
bool Remove(TKey key, TValue value);
/// <summary>Removes all items of a key from the dictionary</summary>
/// <param name="key">Key of the items that will be removed</param>
/// <returns>The number of items that have been removed</returns>
int RemoveKey(TKey key);
}
Его можно скомпилировать на любом из .NET 2.0 вверх и пока я развернул его на Xbox 360, Windows Phone 7, Linux и Unity 3D.
Код лицензируется в соответствии с Common Public License (коротко: все идет, но исправления ошибок в библиотеке код должен быть опубликован) и можно найти в моем репозитории Subversion .
Вот один, который я написал некоторое время назад, которое вы можете использовать.
У него есть класс «MultiValueDictionary», который наследуется от Словаря.
Он также имеет класс расширения, который позволяет вам использовать специальную функцию добавления в любом словаре, где тип значения - это IList; таким образом вы не будете вынуждены использовать пользовательский класс, если вы этого не хотите.
public class MultiValueDictionary<KeyType, ValueType> : Dictionary<KeyType, List<ValueType>>
{
/// <summary>
/// Hide the regular Dictionary Add method
/// </summary>
new private void Add(KeyType key, List<ValueType> value)
{
base.Add(key, value);
}
/// <summary>
/// Adds the specified value to the multi value dictionary.
/// </summary>
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add. The value can be null for reference types.</param>
public void Add(KeyType key, ValueType value)
{
//add the value to the dictionary under the key
MultiValueDictionaryExtensions.Add(this, key, value);
}
}
public static class MultiValueDictionaryExtensions
{
/// <summary>
/// Adds the specified value to the multi value dictionary.
/// </summary>
/// <param name="key">The key of the element to add.</param>
/// <param name="value">The value of the element to add. The value can be null for reference types.</param>
public static void Add<KeyType, ListType, ValueType>(this Dictionary<KeyType, ListType> thisDictionary,
KeyType key, ValueType value)
where ListType : IList<ValueType>, new()
{
//if the dictionary doesn't contain the key, make a new list under the key
if (!thisDictionary.ContainsKey(key))
{
thisDictionary.Add(key, new ListType());
}
//add the value to the list at the key index
thisDictionary[key].Add(value);
}
}
new()
бит? Не думайте, что я видел это раньше.
– mpen
3 October 2010 в 19:28
new()
в коде). @Mark - это ограничение общего параметра , требующее, чтобы переданный в родовом типе имел открытый конструктор без параметров.
– Oded
3 October 2010 в 19:32
where ListType : new()
. (@Mark: Это означает, что ListType
должен иметь открытый конструктор без параметров. Кроме того, я удивлен, что вам нужен этот ответ, который скрывает метод base.Add
, поскольку кажется, что вам не нравится этот аспект ответа Одеда.)
– Dan Tao
3 October 2010 в 19:35
Вы можете легко сделать это из словаря списков:
public class MultiValueDictionary<Key, Value> : Dictionary<Key, List<Value>> {
public void Add(Key key, Value value) {
List<Value> values;
if (!this.TryGetValue(key, out values)) {
values = new List<Value>();
this.Add(key, values);
}
values.Add(value);
}
}
Microsoft просто добавила официальную предварительную версию именно того, что вы ищете (называемый MultiDictionary), доступный через NuGet здесь: https://www.nuget.org/packages/Microsoft.Experimental.Collections/
Информацию об использовании и более подробную информацию можно найти в официальном сообщении в блоге MSDN здесь: http://blogs.msdn.com/b/dotnet/archive/2014/06/ 20 / would-you-like-a-multidictionary.aspx
Я разработчик этого пакета, поэтому дайте мне знать либо здесь, либо в MSDN, если у вас есть какие-либо вопросы о производительности или что-нибудь.
Надеюсь, что это поможет.
myDictionary.Add(2)
- вам не нужно указывать ключ?
– mpen
21 June 2014 в 04:44
Вы можете использовать класс MultiDictionary из PowerCollections .
Он возвращает ICollection {TValue} для запрошенного ключа.
Это должно быть сделано до сих пор ...
public class MultiValueDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
{
private Dictionary<TKey, LinkedList<TValue>> _dict = new Dictionary<TKey, LinkedList<TValue>>();
public void Add(TKey key, TValue value)
{
if(!_dict.ContainsKey(key)) _dict[key] = new LinkedList<TValue>();
_dict[key].AddLast(value);
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
foreach (var list in _dict)
foreach (var value in list.Value)
yield return new KeyValuePair<TKey, TValue>(list.Key, value);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Dictionary<TKey, List<TValue>>
(или аналогичного), поскольку я думаю, что он слишком разоблачает (например, код вызова может добавлять / удалять из значения List<T>
, например).
– Dan Tao
3 October 2010 в 19:27
List
(см. Обсуждение под вашим ответом). @ Dan: Да ... Я собирался реализовать IDictionary
вместо этого, но даже это ... некоторые из методов не имеют смысла.
– mpen
3 October 2010 в 19:58
Вы можете всегда использовать Tuple для вашего второго общего параметра:
var dict = new Dictionary<string,Tuple<string,int,object>>();
dict.Add("key", new Tuple<string,int,object>("string1", 4, new Object()));
Или даже общий список как второй общий параметр:
var dict = new Dictionary<string,List<myType>>();
Это позволит вам привязать несколько значений к одному ключу.
Для удобства использования вы можете создать метод расширения, который будет проверять наличие ключа и дополнение к списку.
add
, чтобы выполнить эту проверку. Это не ресурсоемкий процесс, так как проверка ключа довольно быстрая. Не оптимизируйте перед тем, как нужно i>.
– Oded
3 October 2010 в 19:15
new
метод Add
, а не override
, который я обычно не люблю делать, потому что он нарушает наследование. Кроме того, подписи методов должны быть немного разными, потому что некоторые из них должны фактически возвращать списки TValues, а не только TValue. Наконец, я не совсем уверен, почему вы предложили Tuple .. они не расширяемы?
– mpen
3 October 2010 в 19:22
List
.
– Oded
3 October 2010 в 19:24
Однако здесь - моя попытка с использованием ILookup<TKey, TElement>
и внутренней KeyedCollection
. Убедитесь, что свойство key неизменно. Cross здесь .
public class Lookup<TKey, TElement> : Collection<TElement>, ILookup<TKey, TElement>
{
public Lookup(Func<TElement, TKey> keyForItem)
: base((IList<TElement>)new Collection(keyForItem))
{
}
new Collection Items => (Collection)base.Items;
public IEnumerable<TElement> this[TKey key] => Items[key];
public bool Contains(TKey key) => Items.Contains(key);
IEnumerator<IGrouping<TKey, TElement>>
IEnumerable<IGrouping<TKey, TElement>>.GetEnumerator() => Items.GetEnumerator();
class Collection : KeyedCollection<TKey, Grouping>
{
Func<TElement, TKey> KeyForItem { get; }
public Collection(Func<TElement, TKey> keyForItem) => KeyForItem = keyForItem;
protected override TKey GetKeyForItem(Grouping item) => item.Key;
public void Add(TElement item)
{
var key = KeyForItem(item);
if (Dictionary != null && Dictionary.TryGetValue(key, out var collection))
collection.Add(item);
else
Add(new Grouping(key) { item });
}
public bool Remove(TElement item)
{
var key = KeyForItem(item);
if (Dictionary != null && Dictionary.TryGetValue(key, out var collection)
&& collection.Remove(item))
{
if (collection.Count == 0)
Remove(key);
return true;
}
return false;
}
}
class Grouping : Collection<TElement>, IGrouping<TKey, TElement>
{
public Grouping(TKey key) => Key = key;
public TKey Key { get; }
}
}
Альтернативным для пользовательского типа может быть общее расширение, которое добавляет ключ и значение, если не найден:
public static V getValue<K, V>(this IDictionary<K, V> d, K key) where V : new() {
V v; if (!d.TryGetValue(key, out v)) { v = new V(); d.Add(key, v); } return v; }
Пример использования:
var d = new Dictionary<int, LinkedList<int>>();
d.getValue(1).AddLast(2);
List<T>.Add
имеет амортизированную производительность O (1) и обычно быстрее i>, чемLinkedList<T>.AddLast
, потому что для этого требуется меньше операций.LinkedList<T>.AddLast
может иметь смысл, если вы хотите, чтобы never i> имел изменение размера O (n) (даже если это произойдет редко наList<T>
, который вы только добавляете). – Dan Tao 3 October 2010 в 19:31LinkedList<T>
надList<T>
, когда вы никогда не вставляете / удаляете из середины (там, где действительно светитLinkedList<T>
). Когда вы просто добавляете end i>,LinkedList<T>
просто стоит вам гораздо больше (например, созданиеLinkedListNode<T>
objects = & gt; больше полей для инициализации = & gt; удаление массивов ' преимущество производительности благодаря чрезвычайно оптимизированному доступу к памяти) для очень небольшой выгоды: одинLinkedList<T>.AddLast
в голубой луне будет превосходить одинList<T>.Add
. Остальное будет наоборот. – Dan Tao 3 October 2010 в 19:39