#c# #entity-framework
#c# #entity-framework
Вопрос:
В моей базе данных у меня есть две таблицы: Trucks и TruckTypes. У многих грузовиков может быть много типов грузовиков. Я создал свои модели с помощью конструктора базы данных, и промежуточная таблица (которая содержит только первичные ключи) была проигнорирована, что, как я понимаю, является поведением EF по умолчанию:
Когда я проверяю модели, кажется, что у обеих теперь есть ICollection соответствующей модели, которая, похоже, работает. Проблема возникает, когда я пытаюсь добавить новые элементы или обновить существующие элементы.
На данный момент я обновляю свои записи следующим образом:
using (var db = new Entities())
{
var truckResult = from t in db.ant_Truck
where t.Id == model.Id
select t;
var truck = truckResult.Single();
truck.Name = model.Name;
truck.ant_TruckType.Clear();
foreach (var truckType in model.TruckTypes)
truck.ant_TruckType.Add(new ant_TruckType()
{
Name = truckType.Name,
Disabled = truckType.Disabled
});
truck.Disabled = model.Disabled;
db.SaveChanges();
}
Я думаю, что понимаю проблему: новые ant_truckType
модели добавляются как «новые», а не связываются с существующими записями в таблице «ant_truckType», но я все еще не уверен, как их связать.
Я попытался создать другой метод, который запрашивал таблицу и пытался вернуть ICollection<ant_truckType>
, но это начинает выдавать мне другие ошибки при преобразовании в ICollection:
public ICollection<ant_TruckType> GetDbTruckTypesForTruck(ant_Truck truck)
{
using (var db = new Entities())
{
var result = from tt in db.ant_TruckType
where tt.ant_Truck.Contains(truck)
select tt;
var truckTypes = result.ToList() as ICollection<ant_TruckType>;
return truckTypes;
}
}
Я не уверен, правильно ли я все делаю на данный момент, поскольку я так долго пытался понять, почему это не работает. Какой наиболее эффективный способ попытаться выполнить вышеизложенное?
Заранее спасибо.
Ответ №1:
Типы грузовиков — это справочный список, в котором у грузовика может быть много типов грузовиков. Я бы, вероятно, не стал добавлять коллекцию грузовиков внутри типов грузовиков, чтобы упростить ссылки. Это все еще «многие ко многим», но вместо:
.HasMany(x => x.TruckTypes)
.WithMany(x => x.Trucks)
… с соответствующей конфигурацией таблицы ссылок это было бы упрощено до:
.HasMany(x => x.TruckTypes)
.WithMany()
При обновлении типов грузовиков на грузовике вам понадобится набор всех типов грузовиков для ссылки, затем вы можете разделить его, чтобы определить, какие типы необходимо добавить или удалить:
В идеале вашей модели просто нужно отправить список идентификаторов типа грузовика, которые должны быть связаны с грузовиком. Если вы отправляете типы грузовиков, добавьте шаг, чтобы получить соответствующие идентификаторы, которые вы хотите оставить связанными с грузовиком.
using (var db = new Entities())
{
// Load our truck and eager load its TruckTypes.
var truck = db.ant_Truck.Include(t => t.TruckTypes).Single(t => t.Id == model.Id);
// TODO: Update truck fields ...
// Load all truck types we will want to associate with this truck.
// For smaller sets we can simply load add truck types.
var truckTypes = db.ant_TruckType.Where(tt => model.TruckTypeIds.Contains(tt.Id)).ToList();
var existingTruckTypeIds = truck.TruckTypes.Select(tt => tt.Id).ToList();
var truckTypeIdsToRemove = existingTruckTypeIds.Except(model.TruckTypeIds);
var truckTypeIdsToAdd = model.TruckTypeIds.Except(existingTruckTypeIds);
var truckTypesToRemove = truck.TuckTypes.Where(tt => truckTypeIdsToRemove.Contains(tt.Id));
var truckTypesToAdd = truckTypes.Where(tt => truckTypeIdsToAdd.Contains(tt.Id));
foreach(var truckType in truckTypesToRemove)
truck.TruckTypes.Remove(truckType);
foreach(var truckType in truckTypesToAdd)
truck.TruckTypes.Add(truckType);
db.SaveChanges();
}
Мы загружаем грузовик и включаем его текущие типы грузовиков, затем загружаем ссылки на все типы грузовиков, которые мы хотим связать с грузовиком из контекста БД. Оттуда мы проводим простую инвентаризацию идентификаторов типа грузовика в нашей модели грузовика. Исходя из этого, мы можем использовать Except
для определения идентификаторов типа грузовика, которые необходимо удалить из нашего грузовика и добавить в грузовик. Затем эти результирующие списки идентификаторов могут получать ссылки из типов наших грузовиков (для удаления) и из типов загруженных грузовиков (для добавления).
При двунаправленных ссылках вам могут потребоваться накладные Trucks
расходы на просмотр соответствующей коллекции TruckType
и удаление или добавление из нее текущей корзины. Когда дело доходит до двунаправленных ссылок, я рекомендую избегать их, если они действительно не нужны / полезны. Вы всегда можете фильтровать типы грузовиков по грузовикам, запрашивая критерии для грузовиков, а затем используя SelectMany
для предоставления типов грузовиков.