Удаление всего графа сущностей, включая отношения, с помощью EF Code First - PullRequest
4 голосов
/ 09 июля 2011

У меня есть классы, которые структурированы следующим образом:

public class Forecast
{
    [Key]
    [ForeignKey("Stop")]
    public string Abbreviation { get; set; }
    public virtual Stop Stop { get; set; }
    public virtual List<Direction> Directions { get; set; }
}

public class Direction
{
    public int DirectionId { get; set;}
    public string Abbreviation { get; set;}
    public virtual Forecast Forecast { get; set;}
    public virtual List<Transport> Transports { get; set;}
}

public class Transport
{
    public int TransportId { get; set; }
    public int DirectionId { get; set;}
    public virtual Direction Direction { get; set;}
}

public partial class Stop
{
    [Key]
    public string Abbreviation { get; set; }
    public virtual Forecast Forecast { get; set; }
}

Я разработал эти классы и использовал EF Code First 4.1 для генерации базы данных.Кажется, что CF правильно создает все отношения первичного и внешнего ключей между классами в базе данных (MSSQL).

Моя проблема в том, когда я хочу удалить прогноз.Я думал, что мог сделать что-то вроде следующего:

        using (MyContext ctxt = new MyContext())
        {
            // get a forecast, somehow, not really important
            // The one assumption is I'm absolutely sure it's 
            // Abbreviation key already exists in the database
            // and the list of Forecasts.
            Forecast f;

            ctxt.Forecasts.Remove(f);
        }

Это удаляет объект верхнего уровня из базы данных очень хорошо.Однако все его дочерние объекты - все направления и транспорты - остаются в базе данных и становятся осиротевшими (для их столбца ключевых отношений установлено значение NULL. Я ожидаю, но я не знаю, почему они не просто удалены).Я прибег к повторению вниз по графу объектов и вызову Remove для каждого объекта из соответствующего DbSet в ctxt, но это выглядит как ... неправильный способ сделать это.

Чего мне здесь не хватает?

Почему я не могу просто сказать

ctxt.Forecasts.Remove (f);

и покончить с этим?

Редактировать:

@ Ладислав дал мне правильный ответ - мне нужно было добавить [Обязательно] в свойство Сокращения в Направлении.

Однако я все еще вынужден фактически загружать дочерние объекты, чтобы это работало -Выполнение чего-то простого:

Direction d = f.Directions [0];

приведет к тому, что удаление действительно удалит дочерние объекты.Я хорошо знаю, что это из-за ленивой загрузки.Я думал, что смысл отношений FK и ON CASCADE DELETE заключается в том, что вам не нужно загружать сущности, чтобы удалить их?

Опять же, мне кажется, что мне не хватает чего-то простого.

Ответы [ 2 ]

3 голосов
/ 09 июля 2011

@ Eranga прав, что это делается с помощью ON DELETE CASCADE установки отношения в базе данных, НО вы используете подход, основанный на коде, и EF создает для вас базу данных, поэтому проблема в том, что ваша модель не определена правильно, потому что EF не сделал 't создать каскадное правило для вас.

Почему?Из-за этого:

public class Direction
{
    public int DirectionId { get; set; }
    public string Abbreviation { get; set; }
    public virtual Forecast Forecast { get; set; }
    public virtual List<Transport> Transports { get; set; }
}

Abbreviation является свойством FK, и оно может быть обнуляемым!Таким образом, EF смотрит на вашу модель и видит, что вы определили Direction сущность, для которой Abbreviation можно установить значение NULL, и поэтому она может быть осиротевшей.Измените его на:

public class Direction
{
    public int DirectionId { get; set; }
    [Required]
    public string Abbreviation { get; set; }
    public virtual Forecast Forecast { get; set; }
    public virtual List<Transport> Transports { get; set; }
}

, и удаление Forecast удалит все связанные Direction экземпляры и Transport экземпляры.Stop - это другая история, потому что это родительская сущность для Forecast, поэтому она никогда не будет удалена с помощью Forecast.

Редактировать:

Еще один момент - вы не хотитедобавьте ON DELETE CASCADE к вашим отношениям вручную, потому что EF должен знать о включенных каскадных удалениях.EF использует эту информацию в случае, если вы загрузили связанные объекты.

Если вы поместите правило вручную в базу данных, вы должны использовать свободное отображение и сообщить EF об этом правиле.После принудительного удаления в каскадном режиме каскадного удаления вам не нужно вносить его вручную в базу данных - оно будет создано автоматически во время восстановления базы данных.

3 голосов
/ 09 июля 2011

Этого легко добиться, установив ON DELETE CASCADE при создании внешних ключей в базе данных.

...