Разница между .WithMany () и .WithOptional ()? - PullRequest
23 голосов
/ 24 марта 2011

Ниже приведены две похожие конфигурации API:

WithMany ()

modelBuilder.Entity<Country>()
            .HasRequired(cou => cou.Currency)
            .WithMany()
            .WillCascadeOnDelete(false); 

WithOptional ()

modelBuilder.Entity<Country>()
            .HasRequired(cou => cou.Currency)
            .WithOptional()
            .WillCascadeOnDelete(false);

Я пытаюсь выразить здесь следующее: каждому Country требуется конкретный Currency, но Currency можно присвоить нулю, одной или нескольким странам.

Какое из приведенных выше утвержденийя должен использовать?Или другими словами: в чем именно разница между .WithMany() и .WithOptional() операторами?

1 Ответ

35 голосов
/ 24 марта 2011

Если ваша модель будет выглядеть так:

public class Country
{
    public int CountryId { get; set; }
    public Currency Currency { get; set; }
}

public class Currency
{
    public int CurrencyId { get; set; }
}

тогда ...

modelBuilder.Entity<Country>()
            .HasRequired(cou => cou.Currency)
            .WithOptional()
            .WillCascadeOnDelete(false);

... создает отношение внешнего ключа в базе данных, где CountryId в таблице Countries является первичным ключом и внешним ключом для CurrencyId таблицы Currencies одновременно, поэтому Countries таблица содержит только один столбец CountryId. Запись Currencies может существовать без связанной записи Countries. Но если запись Currencies имеет связанную запись Countries, то не более одной, потому что внешний ключ равен CountryId, который в то же время является первичным ключом и поэтому может находиться только в одной записи. Таким образом, отношения Currencies -> Countries это 1-to-0...1.

Другой пример ...

modelBuilder.Entity<Country>()
            .HasRequired(cou => cou.Currency)
            .WithMany()
            .WillCascadeOnDelete(false);

... создает второй столбец CurrencyId в таблице Countries базы данных, который не может иметь значение NULL и является внешним ключом для CurrencyId таблицы Currencies. Таким образом, здесь возможно, что запись Currencies не имеет связанной записи Countries или одной или нескольких единиц, поскольку внешний ключ теперь является другим столбцом, а не идентичным первичному ключу. Поэтому несколько строк в таблице Countries могут иметь один и тот же внешний ключ. Отношения Currencies -> Countries здесь 1-to-0...n.

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

Если вы возьмете следующий код для двух по-разному настроенных моделей ...

Country country1 = new Country();
Country country2 = new Country();
Currency currency = new Currency();

country1.Currency = currency;
country2.Currency = currency;

context.Countries.Add(country1);
context.Countries.Add(country2);

context.SaveChanges();

... тогда второй случай (.WithMany) работает: мы получаем две новые страны и одну валюту в базе данных.

Однако немного странно то, что во втором случае (.HasOptional) сохраняется только первая Страна, а вторая просто игнорируется. На самом деле я ожидал получить исключение. Я не уверен, следует ли это рассматривать как ошибку.

Edit2

Изменение порядка в приведенном выше примере на ...

context.Countries.Add(country1);
context.Countries.Add(country2);

country1.Currency = currency;
country2.Currency = currency;

... выдает ожидаемое исключение в случае ".HasOptional".

...