Ответ 1
В итоге я решил его выполнить с помощью unicode-escape-символов, отличных от ascii, подобно этому решению.
Однако я до сих пор не знаю, почему это могло произойти...
Моя проблема: вставка набора данных работает в моей локальной машине/базе данных MySQL, но при производстве она вызывает ошибку Duplicate entry for key 'PRIMARY'
. Насколько я могу судить, обе установки эквивалентны.
Моя первая мысль заключалась в том, что это проблема сортировки, но я проверил, что таблицы в обеих базах данных используют utf8_bin
.
Стол пуст, и я делаю .Distinct()
в коде, поэтому не должно быть дубликатов записей.
Таблица, о которой идет речь:
CREATE TABLE `mytable` (
`name` varchar(100) CHARACTER SET utf8 NOT NULL,
`appid` int(11) NOT NULL,
-- A few other irrelevant fields
PRIMARY KEY (`name`,`appid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
Database.cs
:
[DbConfigurationType(typeof(MySql.Data.Entity.MySqlEFConfiguration))]
public class Database : DbContext
{
public DbSet<MyTable> MyTable { get; set; }
public static Database Get()
{
/* Not important */
}
//etc.
}
MyTable.cs
:
[Table("mytable")]
public class MyTable : IEquatable<MyTable>, IComparable, IComparable<MyTable>
{
[Column("name", Order = 0), Key, Required, DatabaseGenerated(DatabaseGeneratedOption.None)]
public string Name
{
get { return _name; }
set { _name = value.Trim().ToLower(); }
}
private string _name;
[Column("appid", Order = 1), Key, Required, DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ApplicationId { get; set; }
//Equals(), GetHashCode(), CompareTo(), ==() etc. all auto-generated by Resharper to use both Name and ApplicationId.
//Have unit-tests to verify they work correctly.
}
Затем, используя его:
using(Database db = Database.Get())
using(DbContextTransaction transaction = db.Database.BeginTransaction(IsolationLevel.ReadUncommitted))
{
IEnumerable<MyTable> newEntries = GetNewEntries();
//Verify no existing entries already in the table; not necessary to show since table is empty anyways
db.MyTable.AddRange(newEntries.Distinct());
}
Я не понимаю, как могут быть дублированные записи в базе данных после выполнения .Distinct()
в коде при использовании utf8_bin
, тем более, что он работает на одной машине, но не в другой. У кого-нибудь есть идеи?
В итоге я решил его выполнить с помощью unicode-escape-символов, отличных от ascii, подобно этому решению.
Однако я до сих пор не знаю, почему это могло произойти...
Я бы исследовал следующие моменты:
SHOW VARIABLES LIKE "%version%";
SELECT HEX(name)
, чтобы узнать, как кодируются данные, для повторяющейся строки.https://dev.mysql.com/doc/refman/5.7/en/charset-unicode-utf8mb3.html
https://dev.mysql.com/doc/refman/5.7/en/charset-unicode-utf8mb4.html
Предполагая, что на машине dev данные вставляются из новой установки, а на производственной машине данные могут быть вставлены с более старой версией, а затем обновлен сервер, я бы проверял, в частности, если необходимы действия ( и были выполнены), чтобы правильно выполнить процесс обновления.
В частности, см. эти разделы (для правильной версии) в справочном руководстве MySQL:
https://dev.mysql.com/doc/refman/5.7/en/checking-table-incompatibilities.html
При необходимости перестройте индексы.
https://dev.mysql.com/doc/refman/5.7/en/rebuilding-tables.html
Изменить (2016-10-12)
Все вышеописанное основное внимание уделяется таблице и хранению.
Другая часть для проверки - это соединение между клиентом и сервером с такими переменными, как character_set_connection
.
Пожалуйста, проверьте все системные переменные, связанные с набором символов, для их сравнения.
mysql> show variables like "%character%";
+--------------------------+-------------------------------------------+
| Variable_name | Value |
+--------------------------+-------------------------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /home/malff/GIT_TRUNK/sql/share/charsets/ |
+--------------------------+-------------------------------------------+
8 rows in set (0.02 sec)
Обе машины используют одни и те же драйверы базы данных? У меня были аналогичные проблемы с EF и Oracle, когда установлены разные драйверы.
EDIT:
Этот документ
https://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html
говорит, что до MySQL 5.5.3 символы Юникода были сохранены с использованием макс. 3 байта на символ и после этого были сохранены с использованием 4 байтов. Это может объяснить разницу в том, является ли ключ уникальным. Разница вступает в игру, когда используются "дополнительные символы", поскольку старые версии не могут хранить эти символы вообще.
Являются ли ваши две базы данных по разные стороны разрыва (MySQL 5.5.3)?
Я думаю, это может быть потому, что определенные символы имеют разные значения, основанные на среде, поэтому обычно рекомендуется избегать этих специальных символов, прежде чем строка будет использоваться как значение данных.
Проверьте это: http://dev.mysql.com/doc/refman/5.7/en/string-literals.html#character-escape-sequences