Сохраните имена пользователей, как было предложено Фрэнком, но когда вы сохраняете имена пользователей, используйте функцию runTransaction в Firebase, чтобы убедиться, что имя пользователя не занято. Эта функция гарантируется Firebase как атомная операция, поэтому вы можете быть уверены в отсутствии столкновения
firebaseRef.child("usernames").child(username).runTransaction(new Transaction.Handler() {
@Override
public Transaction.Result doTransaction(MutableData mutableData) {
if (mutableData.getValue() == null) {
mutableData.setValue(authData.getUid());
return Transaction.success(mutableData);
}
return Transaction.abort();
}
@Override
public void onComplete(FirebaseError firebaseError, boolean commited, DataSnapshot dataSnapshot) {
if (commited) {
// username saved
} else {
// username exists
}
}
});
Несколько подсказок, которые я нашел в последнее время.
Намного лучше использовать TableAdapter FillByDataXXXX () методы вместо GetDataByXXXX () методы, потому что DataTable, переданный в метод заполнения, может быть опрошен для подсказок:
Недавно, я обернул некоторый код запроса в подкласс ConstraintException, это оказалось полезной начальной точкой для отладки.
Использование C# В качестве примера:
Example.DataSet.fooDataTable table = new DataSet.fooDataTable();
try
{
tableAdapter.Fill(table);
}
catch (ConstraintException ex)
{
// pass the DataTable to DetailedConstraintException to get a more detailed Message property
throw new DetailedConstraintException("error filling table", table, ex);
}
Вывод:
DetailedConstraintException: заливка таблицы перестала работать
Об ошибках сообщают для ConstraintExceptionHelper. DataSet+fooDataTable [нечто]
Столбцы по ошибке: [1]
[PRODUCT_ID] - строки итогов влияли: 1085
Ошибки строки: [4]
[Столбец 'PRODUCT_ID' вынужден быть уникальным. Значение '1' уже присутствует.] - строки итогов влияли: 1009
[Столбец 'PRODUCT_ID' вынужден быть уникальным. Значение '2' уже присутствует.] - строки итогов влияли: 20
[Столбец 'PRODUCT_ID' вынужден быть уникальным. Значение '4' уже присутствует.] - строки итогов влияли: 34
[Столбец 'PRODUCT_ID' вынужден быть уникальным. Значение '6' уже присутствует.] - строки итогов влияли: 22
----> Система. Данные. ConstraintException: Не удалось включить ограничения. Одна или несколько строк содержат значения, нарушающие непустые, уникальные ограничения, или внешнего ключа.
Я не знаю - ли это слишком много кода для включения в Переполнение стека, отвечают, но вот класс C# полностью.Отказ от ответственности: это работает на меня, не стесняйтесь использовать/изменять в качестве соответствующих.
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
namespace ConstraintExceptionHelper
{
/// <summary>
/// Subclass of ConstraintException that explains row and column errors in the Message property
/// </summary>
public class DetailedConstraintException : ConstraintException
{
private const int InitialCountValue = 1;
/// <summary>
/// Initialises a new instance of DetailedConstraintException with the specified string and DataTable
/// </summary>
/// <param name="message">exception message</param>
/// <param name="ErroredTable">DataTable in error</param>
public DetailedConstraintException(string message, DataTable erroredTable)
: base(message)
{
ErroredTable = erroredTable;
}
/// <summary>
/// Initialises a new instance of DetailedConstraintException with the specified string, DataTable and inner Exception
/// </summary>
/// <param name="message">exception message</param>
/// <param name="ErroredTable">DataTable in error</param>
/// <param name="inner">the original exception</param>
public DetailedConstraintException(string message, DataTable erroredTable, Exception inner)
: base(message, inner)
{
ErroredTable = erroredTable;
}
private string buildErrorSummaryMessage()
{
if (null == ErroredTable) { return "No errored DataTable specified"; }
if (!ErroredTable.HasErrors) { return "No Row Errors reported in DataTable=[" + ErroredTable.TableName + "]"; }
foreach (DataRow row in ErroredTable.GetErrors())
{
recordColumnsInError(row);
recordRowsInError(row);
}
StringBuilder sb = new StringBuilder();
appendSummaryIntro(sb);
appendErroredColumns(sb);
appendRowErrors(sb);
return sb.ToString();
}
private void recordColumnsInError(DataRow row)
{
foreach (DataColumn column in row.GetColumnsInError())
{
if (_erroredColumns.ContainsKey(column.ColumnName))
{
_erroredColumns[column.ColumnName]++;
continue;
}
_erroredColumns.Add(column.ColumnName, InitialCountValue);
}
}
private void recordRowsInError(DataRow row)
{
if (_rowErrors.ContainsKey(row.RowError))
{
_rowErrors[row.RowError]++;
return;
}
_rowErrors.Add(row.RowError, InitialCountValue);
}
private void appendSummaryIntro(StringBuilder sb)
{
sb.AppendFormat("Errors reported for {1} [{2}]{0}", Environment.NewLine, ErroredTable.GetType().FullName, ErroredTable.TableName);
}
private void appendErroredColumns(StringBuilder sb)
{
sb.AppendFormat("Columns in error: [{1}]{0}", Environment.NewLine, _erroredColumns.Count);
foreach (string columnName in _erroredColumns.Keys)
{
sb.AppendFormat("\t[{1}] - rows affected: {2}{0}",
Environment.NewLine,
columnName,
_erroredColumns[columnName]);
}
}
private void appendRowErrors(StringBuilder sb)
{
sb.AppendFormat("Row errors: [{1}]{0}", Environment.NewLine, _rowErrors.Count);
foreach (string rowError in _rowErrors.Keys)
{
sb.AppendFormat("\t[{1}] - rows affected: {2}{0}",
Environment.NewLine,
rowError,
_rowErrors[rowError]);
}
}
/// <summary>
/// Get the DataTable in error
/// </summary>
public DataTable ErroredTable
{
get { return _erroredTable; }
private set { _erroredTable = value; }
}
/// <summary>
/// Get the original ConstraintException message with extra error information
/// </summary>
public override string Message
{
get { return base.Message + Environment.NewLine + buildErrorSummaryMessage(); }
}
private readonly SortedDictionary<string, int> _rowErrors = new SortedDictionary<string, int>();
private readonly SortedDictionary<string, int> _erroredColumns = new SortedDictionary<string, int>();
private DataTable _erroredTable;
}
}