#c# #entity-framework-core
Вопрос:
Я получаю следующую ошибку с кодом ниже:
- Я объявляю свой репозиторий с помощью AddScoped в своем api restful, когда я использую это. По-прежнему не работает. (услуги.AddScoped<ICampRepository, CampRepository>();)
- Я пробовал использовать AsNoTracking(), но SaveChanges не работает. Даже когда я говорю EF, что состояние изменилось, я снова получаю ту же ошибку.
Экземпляр сущности типа «Конференц-зал» не может быть отслежен, поскольку другой экземпляр с тем же значением ключа для {‘Id’} уже отслеживается. При присоединении существующих сущностей убедитесь, что присоединен только один экземпляр сущности с заданным значением ключа. Рассмотрите возможность использования DbContextOptionsBuilder.Позволяет чувствительному каталогизированию» видеть конфликтующие ключевые значения.
public async Task<bool> AddRangeTalksAsync(List<Talk> talksToBulkInsert, string moniker)
{
try
{
IQueryable<Camp> query = _context.Camps.Where(c => c.Moniker == moniker);
Camp camp = await query.FirstOrDefaultAsync();
camp.Talks.AddRange(talksToBulkInsert);
await _context.SaveChangesAsync();
return true;
}
catch (Exception ex)
{
return false;
}
}
Ниже приведен пример списка объектов, которые я пытаюсь вставить. Один работает, но не больше, чем один не работает.
[
{
"id": 0,
"campId": 0,
"title": "Talk for 'CompuGen Core Code Camp #4' for conference room 'Conference Room #1' for day 1 hour 1",
"abstract": "This talk is interesting, you will like it.",
"level": 1,
"food": "Bread",
"beverage": "Water",
"swag": "Talk T-Shirt and a notebook",
"startTime": "2022-01-03T08:00:00",
"endTime": "2022-01-03T09:00:00",
"conferenceRoom": {
"id": 307,
"campId": 34,
"conferenceRoomName": "Conference Room #1",
"conferenceRoomCapacity": 56
},
"talkSpeakers": [],
"talkAttendees": [],
"ratings": []
},
{
"id": 0,
"campId": 0,
"title": "Talk for 'CompuGen Core Code Camp #4' for conference room 'Conference Room #1' for day 1 hour 2",
"abstract": "This talk is interesting, you will like it.",
"level": 1,
"food": "Bread",
"beverage": "Water",
"swag": "Talk T-Shirt and a notebook",
"startTime": "2022-01-03T08:00:00",
"endTime": "2022-01-03T09:00:00",
"conferenceRoom": {
"id": 307,
"campId": 34,
"conferenceRoomName": "Conference Room #1",
"conferenceRoomCapacity": 56
},
"talkSpeakers": [],
"talkAttendees": [],
"ratings": []
}
]
Кроме того, схема базы данных выглядит так из сущностей, которые я создал в EF CORE.
То, что я ищу, — это то, как сохранить эту схему без изменений и иметь возможность создавать несколько конференц-залов для лагеря за один раз, но это не работает.
Комментарии:
1. То, как вы это сделали, слишком сложно, могло бы быть проще. Вы пытаетесь создать новый конференц-зал, когда создаете talk, или просто добавляете конференц-зал 307, который уже существует?
2. Просто пытаюсь создать коллекцию конференц-залов, добавленных в лагерь.
Ответ №1:
Попробуйте это
var camp = await _context.Camps.Where(c => c.Moniker == moniker).FirstOrDefaultAsync();
if (camp!=null)
{
var campId=camp.Id;
talksToBulkInsert.ForEach(i=> i.CampId=campId);
_context.Talks.AddRange(talksToBulkInsert);
await _context.SaveChangesAsync()
}
вы тоже можете попробовать это, но это не так надежно
var camp = await _context.Camps.Include(i=> i.Talks)
.Where(c => c.Moniker == moniker).FirstOrDefaultAsync();
camp.Talks.AddRange(talksToBulkInsert);
но сначала вам нужно исправить структуру таблиц данных, например
"conferenceRoom": {
"id": 307,
"campId": 34,
.....
Как получилось, что у дочерней записи есть campId, а у родительской-нет? у вас вообще не должно быть здесь никакого кампида. И их гораздо больше. Сначала вам нужно создать действительную базу данных и только после этого попытаться что-то добавить или обновить.
Комментарии:
1. Я попробовал тот первый метод, который вы предложили, и все равно получил ту же проблему.
2. Я также попробовал второй метод, и все равно получаю ту же проблему.
3. @BillBlair Я тоже не ожидал ничего хорошего, так как ваша структура данных полна ошибок. Он никогда не будет работать должным образом.
4. Хорошо, так что же в этом плохого? Конференц — зал-это то, из-за чего он выходит из строя, как я должен изменить структуру данных?
5. Json действителен, поэтому я не уверен, что с ним не так.
Ответ №2:
Хорошо, я думаю, что на данный момент я это исправил. Что я сделал, так это изменил способ создания стола переговоров. Для внешнего ключа конференц-зала у меня есть следующее для OnDelete: OnDelete: ReferentialAction.Никаких действий. Таким образом, это удалит циклическую ссылку между ConferenceRoomId и ConferenceRoom. Однако, если конференц-зал будет удален, соответствующий разговор удален не будет. Это может быть нежелательно, но я могу удалить эти данные другим способом, если это необходимо.
Мое новое Определение для выступления:
public class Talk
{
/// <summary>
/// Constructor for Talk.
/// </summary>
public Talk()
{
Ratings = new List<Rating>();
TalkSpeakers = new List<TalkSpeaker>();
TalkAttendees = new List<TalkAttendee>();
}
#pragma warning disable 1591 //Ingore compiler warning for not having XML comments.
[ExcludeFromCodeCoverage]
public int Id { get; set; }
[ExcludeFromCodeCoverage]
public int CampId { get; set; }
/// <summary>
/// Navigation property to a Camp.
/// </summary>
public Camp Camp { get; set; }
/// <summary>
/// Navigation property to ratings.
/// </summary>
public List<Rating> Ratings { get; set; }
public int ConferenceRoomId { get; set; }
/// <summary>
/// Navigation property to a Conference Room.
/// </summary>
public ConferenceRoom ConferenceRoom { get; set; }
public string Title { get; set; }
public string Abstract { get; set; }
public int? Level { get; set; }
public string Food { get; set; }
public string Beverage { get; set; }
public string SWAG { get; set; }
public DateTime startTime { get; set; } = DateTime.MinValue;
public DateTime endTime { get; set; } = DateTime.MinValue;
/// <summary>
/// TalkSpeaker joins Talk and Speaker together.
/// </summary>
public List<TalkSpeaker> TalkSpeakers { get; set; }
/// <summary>
/// TalkAttendee joins Talk and Attendee together.
/// </summary>
public List<TalkAttendee> TalkAttendees { get; set; }
#pragma warning restore 1591
}
Изменение внешнего ключа в конференц-залах, чтобы не было круговой ссылки между идентификатором конференц-зала и конференц-залом.
migrationBuilder.CreateTable(
name: "Talks",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
CampId = table.Column<int>(nullable: false),
ConferenceRoomId = table.Column<int>(nullable: false),
Title = table.Column<string>(nullable: true),
Abstract = table.Column<string>(nullable: true),
Level = table.Column<int>(nullable: true),
Food = table.Column<string>(nullable: true),
Beverage = table.Column<string>(nullable: true),
SWAG = table.Column<string>(nullable: true),
startTime = table.Column<DateTime>(nullable: false),
endTime = table.Column<DateTime>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Talks", x => x.Id);
table.ForeignKey(
name: "FK_Talks_Camps_CampId",
column: x => x.CampId,
principalTable: "Camps",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_Talks_ConferenceRooms_ConferenceRoomId",
column: x => x.ConferenceRoomId,
principalTable: "ConferenceRooms",
principalColumn: "Id",
onDelete: ReferentialAction.NoAction);
});