EF 4.1 - 模型关系

21

我正在尝试使用EF 4.1的RC版本创建一个快速的ASP.NET MVC 3应用程序,我有两个模型:

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; }
}

当我尝试插入一个新的Race时,出现了以下错误:

无法确定'rcommander.Models.Race'和'rcommander.Models.Address'之间关联的主要端点。必须使用关系流畅API或数据注释显式配置此关联的主要端点。

难道它不能自动将RaceId识别为Races表的主键,AddressId作为Addresses表的外键吗?我有什么遗漏的地方吗?

谢谢!

6个回答

21

这里的问题似乎是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; }
}

在第二个实体中跳过Race的引用。


4
这样做会不会使地址失去导航功能? - Yngve B-Nilsen
1
是的,它将从地址中删除导航功能,并将其映射为我在答案中描述的一对多关系。 - Ladislav Mrnka
1
那么有没有一种方法(也许通过属性)来实现交叉引用中的关系呢? - Shimmy Weitzhandler
为什么您实际需要公共整数?AddressId { get; set; }? - Nikos

18

这里的问题在于地址(Address)和种族(Race)之间存在1:1的关系!你可能需要将其映射为1:N,因此需要修改地址(Address)如下:

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,那么您不能在Race中使用AddressId,但是Address中的AddressId必须是Race外键,因为Entity Framework只能通过“共享”主键来实现1:1。


3
请更新您的答案,展示如何使用共享主键的方式进行1:1关系。我希望能够双向访问,例如:Race.Address和Address.Race。如果可能,请在您的示例中保留Race和Address这两个实体名称。谢谢。 - Leniel Maccaferri
1
@Leniel:请参考这个答案:https://dev59.com/mG435IYBdhLWcg3wfQF9#5388658。我觉得这应该是你所需要的。 - Ladislav Mrnka

8

对于一对一的关系,您需要在第二个类中添加“[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; }

}

5

将我们的关联变成一对一的方法之一是使它们双向。也就是说,向Address类添加一个新的导航属性,类型为User和另一个类型为Shipment。 - 这似乎不起作用。我得到一个“无法确定类型之间关联的主要端点...这个关联的主要端点必须使用关系流畅API或数据注释进行显式配置。” - Karan

4

按照惯例,它将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]属性表示它应该是主键。
如果不想这样,需要将主键重命名为public int Id {get; set; }

1
无论使用哪种方法都会出现相同的错误。如果有影响的话,我在Global.asax的Application_Start中设置了我的DB Initializer为DropCreateDatabaseIfModelChanges。 - Mike
1
嗯...检查一下我的更新...也许ForeignKeyAttribute是你需要的? - Yngve B-Nilsen
1
这里不是需要InverseProperty("RaceId")吗,而不是ForeignKey? - Joe
假设我们有InverseProperty("RaceId") - 你可以这样做:var address = new Address(); var race = new Race(){Address = address} - 然后通过address.Race获取race吗? - Karan

0

我认为这个问题也可以这样解决... 我假设一个地址不需要与种族相关联,但是一个种族必须始终与一个地址相关联。我曾经在患者和事件方面遇到过同样的问题,并且通过使用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; }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接