EF 4.1 — модельные отношения

Я пытаюсь создать быстрое приложение ASP.NET MVC 3, используя RC-версию EF 4.1. У меня есть две модели:

public class Race
{
    public int RaceId { get; set; }
    public string RaceName { get; set; }
    public string RaceDescription { get; set; }
    public DateTime? RaceDate { get; set; }
    public decimal? Budget { get; set; }
    public Guid? UserId { get; set; }
    public int? AddressId { get; set; }

    public virtual Address Address { get; set; }
}

и

public class Address
{
    public int AddressId { get; set; }
    public string Street { get; set; }
    public string StreetCont { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }

    public virtual Race Race { get; set; }
}

Я получаю следующую ошибку при попытке вставить новую гонку:

Не удалось определить главный конец ассоциации между типами «rcommander.Models.Race» и «rcommander.Models.Address». Основной конец этой ассоциации должен быть явно настроен с помощью API-интерфейса Fluent для отношений или аннотаций данных.

Разве он не должен автоматически распознавать RaceId как первичный ключ таблицы Races и AddressId как FK для таблицы Addresses? Я что-то упускаю?

Спасибо!




Ответы (6)


Проблема здесь, по-видимому, в том, что EntityFramework не может распознать, где находится передний ключ, поскольку вы держите перекрестные ссылки в обоих объектах. Не зная, чего вы хотите добиться, я могу предложить что-то вроде этого:

public class Race
{
  public int RaceId { get; set; }
  public string RaceName { get; set; }
  public string RaceDescription { get; set; }
  public DateTime? RaceDate { get; set; }
  public decimal? Budget { get; set; }
  public Guid? UserId { get; set; }

  public int? AddressId { get; set; }
  public virtual Address Address { get; set; }
}

public class Address
{
  public int AddressId { get; set; }
  public string Street { get; set; }
  public string StreetCont { get; set; }
  public string City { get; set; }
  public string State { get; set; }
  public string ZipCode { get; set; }
}

Пропуск ссылки на расу во втором объекте.

person tpeczek    schedule 18.03.2011
comment
не удалит ли это навигационные возможности из адреса? - person Yngve B-Nilsen; 18.03.2011
comment
Да, он удалит возможность навигации по адресу и сопоставит его как отношение «один ко многим», как я описал в своем ответе. - person Ladislav Mrnka; 18.03.2011
comment
Итак, есть ли способ достичь (возможно, с помощью атрибутов) отношения в перекрестной ссылке? - person Shimmy Weitzhandler; 11.05.2012
comment
зачем вам вообще нужен public int? Идентификатор адреса { получить; набор; }? - person Nikos; 25.01.2013

Проблема здесь в соотношении 1:1 между адресом и расой! Вероятно, вы хотите отобразить его как 1:N, поэтому вам нужно изменить адрес на:

public class Address
{
  public int AddressId { get; set; }
  public string Street { get; set; }
  public string StreetCont { get; set; }
  public string City { get; set; }
  public string State { get; set; }
  public string ZipCode { get; set; }

  public virtual ICollection<Race> Races { ... }
}

Если вы хотите использовать 1:1, вы не можете использовать AddressId в Race, но AddressId в Address должен быть внешним ключом Race, потому что структура сущностей может достичь 1:1 только при «совместном использовании» первичного ключа.

person Ladislav Mrnka    schedule 18.03.2011
comment
Не могли бы вы обновить свой ответ, чтобы показать, как использовать 1: 1 с использованием общего первичного ключа? Я хотел бы иметь двунаправленный способ доступа: Race.Address и Address.Race. Сохраняйте расу и адрес, если это возможно в вашем примере. Спасибо. - person Leniel Maccaferri; 28.04.2011
comment
@Leniel: проверьте этот ответ: stackoverflow.com/questions/5388077/ Я думаю, это то, что вы ищете. - person Ladislav Mrnka; 28.04.2011

Для отношения «один к одному» вам необходимо добавить атрибут «[required]» во второй класс. Увидеть ниже:

public class Race
{
  public int RaceId { get; set; }
  public string RaceName { get; set; }
  public string RaceDescription { get; set; }
  public DateTime? RaceDate { get; set; }
  public decimal? Budget { get; set; }
  public Guid? UserId { get; set; }

  public int? AddressId { get; set; }
  public virtual Address Address { get; set; }
 }

public class Address
{
 public int AddressId { get; set; }
 public string Street { get; set; }
 public string StreetCont { get; set; }
 public string City { get; set; }
 public string State { get; set; }
 public string ZipCode { get; set; }

 [required]
 public Race Race { get; set; }

}
person Ehsan    schedule 15.07.2012

Есть хороший пост: Associations in EF Code First CTP5: Part 2 — Shared Primary Key Associations

http://weblogs.asp.net/manavi/archive/2010/12/19/entity-association-mapping-with-code-first-one-to-one-shared-primary-key-associations.aspx

person Roeland Jimenez    schedule 20.04.2011
comment
Один из способов сделать наши ассоциации однозначными — сделать их двунаправленными. То есть добавление нового свойства навигации в класс Address типа User и еще одного свойства типа Shipment. - это, кажется, не работает. Я получаю сообщение Невозможно определить основной конец ассоциации между типами... Основной конец этой ассоциации должен быть явно настроен с использованием API-интерфейса Fluent отношения или аннотаций данных. - person Karan; 02.10.2012

Он распознает Id как первичный ключ по соглашению. Итак, что вам нужно сделать:

public class Race
{
    [Key]
    public int RaceId { get; set; }
    public string RaceName { get; set; }
    public string RaceDescription { get; set; }
    public DateTime? RaceDate { get; set; }
    public decimal? Budget { get; set; }
    public Guid? UserId { get; set; }
    public int? AddressId { get; set; }

    public virtual Address Address { get; set; }
}
and

public class Address
{
    [Key]
    public int AddressId { get; set; }
    public string Street { get; set; }
    public string StreetCont { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }

    [ForeignKey("RaceId")] // Maybe telling it what the ForeignKey is will help?
    public virtual Race Race { get; set; }
}

Атрибут [Key] указывает, что это должен быть PrimaryKey.

Если вы этого не хотите, вам нужно переименовать первичные ключи просто в public int Id {get; set; }.

person Yngve B-Nilsen    schedule 18.03.2011
comment
Одна и та же ошибка при использовании любого метода. У меня есть инициализатор БД в Application_Start в Global.asax для DropCreateDatabaseIfModelChanges, если это имеет значение. - person Mike; 18.03.2011
comment
Хм... Проверьте мое обновление.. Может быть, вам нужен атрибут ForeignKeyAttribute? - person Yngve B-Nilsen; 18.03.2011
comment
Разве здесь не нужно InverseProperty(RaceId), а не ForeignKey? - person Joe; 02.12.2011
comment
Предполагая, что у нас есть InverseProperty(RaceId) - могли бы вы: var address = new Address(); var race = new Race(){Address = address} - а затем получить расу через address.Race? - person Karan; 02.10.2012

Я думаю, что это будет решаться также так... Я предположил, что адрес не обязательно должен быть связан с расой, но раса всегда должна быть связана с адресом. У меня была такая же проблема с пациентами и инцидентами, и я решил ее с помощью InverseProperty, которая на самом деле такая же, как с внешним ключом, но в другом направлении.

public class Race
{
  public int RaceId { get; set; }
  public string RaceName { get; set; }
  public string RaceDescription { get; set; }
  public DateTime? RaceDate { get; set; }
  public decimal? Budget { get; set; }
  public Guid? UserId { get; set; }

  public int AddressId { get; set; }

  [ForeignKey("AddressId")]
  public virtual Address Address { get; set; }
 }

public class Address
{
 public int AddressId { get; set; }
 public string Street { get; set; }
 public string StreetCont { get; set; }
 public string City { get; set; }
 public string State { get; set; }
 public string ZipCode { get; set; }

 public int? RaceId { get; set; }
 [InverseProperty("RaceId")]
 public Race Race { get; set; }

}
person Thanasis Ioannidis    schedule 21.08.2012