У меня есть следующая модель:
[Table("Facts")]
public partial class Facts
{
[Key]
public Guid ID { get; set; }
public Guid UserID { get; set; }
[ForeignKey(nameof(UserID))]
public Users Users { get; set; }
//other properties are ommitted
}
Код миграции:
migrationBuilder.CreateTable(
name: "Facts",
columns: table => new
{
ID = table.Column<Guid>(nullable: false),
UserID = table.Column<Guid>(nullable: false),
//other properties are ommitted
},
constraints: table =>
{
table.PrimaryKey("PK_Facts", x => x.ID);
table.ForeignKey(
name: "FK_Facts_Users_UserID",
column: x => x.UserID,
principalTable: "Users",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
});
Поскольку у него есть свойство навигации, я установил для него существующий идентификатор (это необходимо).
Это метод сохранения:
public async Task SaveData<T>(List<T> data, bool isNew) where T : class
{
if (data == null)
throw new ArgumentNullException(nameof(data));
try
{
if (isNew)
context.Set<T>().AddRange(data);
else
{
context.Set<T>().AttachRange(data);
data.ForEach(d => (context as DbContext).Entry(d).State = EntityState.Modified);
}
await context.SaveChangesAsync();
}
catch (Exception ex)
{
throw;
}
}
Когда я вхожу в метод сохранения, у меня следующее состояние (идентификатор установлен, объект свойства навигации имеет значение null):
После AddRange
у меня следующее состояние (идентификатор установлен, объект свойства навигации имеет значение , не ноль ):
Внутри улова я получаю следующее исключение:
Microsoft.EntityFrameworkCore.DbUpdateException: произошла ошибка
при обновлении записей. Смотрите внутреннее исключение для деталей. --->
Microsoft.Data.Sqlite.SqliteException: ошибка SQLite 19: «ИНОСТРАННЫЙ КЛЮЧ»
ограничение не выполнено '
Похоже, он пытается добавить объект свойства навигации в качестве нового элемента в базу данных.
Как я могу предотвратить повторную вставку уже существующего свойства навигации?
UPDATE
После включения ведения журнала SQL я получаю следующую информацию (@ p0 - это PK, @ p18 - это FK):
Failed executing DbCommand (105ms) [Parameters=[@p0='84ddca86-3f8a-41f1-aaed-2c65bd1cb384' (DbType = String),...@p18='e33f7939-bc35-4d82-b68b-e1cc0cf32ff1' (DbType = String)...]
INSERT INTO "Facts" ("ID", ... "UserID",...)
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14, @p15, @p16, @p17, @p18, @p19, @p20, @p21, @p22, @p23, @p24, @p25, @p26, @p27, @p28, @p29);
Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 19: 'FOREIGN KEY constraint failed'.
UPDATE2
Я провел тестирование эмулятора и обнаружил следующее.
Данные таблицы Users
изначально вставляются с помощью сценария SQL со следующим кодом:
public async virtual Task ExecuteCommandAsync(string sqlCommand)
{
await context.Database.ExecuteSqlCommandAsync(new RawSqlString(sqlCommand));
}
Как видите, запись существует:
Когда я сохраняю несвязанные данные с помощью SaveData
, его идентификатор сохраняется как двоичные данные :
Так, может быть, Entity Framework Core каким-то образом запутывается при попытке преобразовать двоичные данные в текст? До сих пор не знаю, почему извлечение работает нормально.