Разница между .WithMany() и .WithOptional()?

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

Со многими()

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

С необязательным()

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

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

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


person Ingmar    schedule 24.03.2011    source источник
comment
Вы имели в виду, что заголовок и описание относятся к .WithMany() и .WithOptional() вместо .HasMany() и .HasOptional()? Я отправил правку.   -  person Tom Robinson    schedule 09.01.2012


Ответы (1)


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

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 базы данных, который не может быть нулевым и является внешним ключом для 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) сохраняется только первая Страна, вторая просто игнорируется. На самом деле я ожидал получить исключение. Я не уверен, следует ли это считать ошибкой.

Изменить2

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

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

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

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

person Slauma    schedule 24.03.2011
comment
А, понял. Таким образом, .HasOptional() соответствует отношениям 1 ‹-> 0|1, а .HasMany() — отношениям 1 ‹-> 0|n. Большой. Это то, что я хотел знать. Спасибо большое!!! - person Ingmar; 24.03.2011
comment
@Ingmar: Взгляните на мое редактирование, возможно, стоит знать. Я только что обнаружил, что, возможно, есть ошибка с отношением 1 ‹-› 0|1. - person Slauma; 24.03.2011