在Entity Framework 4.1 Fluent API中具有连接表和可选关系的一对多

GoC*_*ado 5 entity-framework ef-code-first entity-framework-4.1

再次使用无法更改的旧数据库,并使用带有Fluent API的Entity Framework 4.1来仅读取数据.

public class Client
{
  [Key]
  public int ClientID { get; set; }
  public string Name { get; set ;}

  public virtual ICollection<Phone> Phones { get; set; }
}

public class Phone
{
  [Key]
  public int PhoneID { get; set; }
  public string Number { get; set; }

  public virtual Client Client { get; set; }
}

public class ClientPhone
{
  [Key]
  [Column(Order=0)]
  public int ClientID { get; set; }

  [Key]
  [Column(Order=1)]
  public int PhoneID { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我希望客户端有很多电话,但电话应该只有一个可选的客户端. 注意:电话应该只有0 | 1个客户端.我不想要多对多. 所以我尝试了以下内容:

modelBuilder.Entity<Client>()
  .HasMany(c => c.Phones)
  .WithOptional(p => p.Client)
  .Map(m =>
    {
      m.MapKey("ClientID");
      m.ToTable("ClientPhone");
    });

modelBuilder.Entity<Phone>()
  .HasOptional(p => p.Client)
  .WithMany(c => c.Phones)
  .Map(m =>
    {
      m.MapKey("PhoneID");
      m.ToTable("ClientPhone");
    });
Run Code Online (Sandbox Code Playgroud)

我尝试了几种排列,通常会收到一个错误:"类型中的每个属性名称都必须是唯一的".

谢谢您的帮助.

用答案编辑

以下是我对实体类所做的修改.可以从一个客户端导航到多个电话,从一个电话导航到一个客户端,但您必须通过ClientPhone连接表.

[Table("Client")]
public class Client
{
  [Key]
  [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
  public int ClientID { get; set; }

  public string Name { get; set ;}

  public virtual ICollection<Phone> Phones { get; set; } // Client has * Phones
}

[Table("Phone")]
public class Phone
{
  [Key]
  [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
  public int PhoneID { get; set; }

  public string Number { get; set; }

  public virtual Client Client { get; set; } // Phone has 0|1 Client
}

[Table("ClientPhone")]
public class ClientPhone
{
  // Removed the Key attribute
  public int ClientID { get; set; }

  [Key] // Left the Key on the 0|1 side
  [ForeignKey("Phone")]
  public int PhoneID { get; set; }

  public virtual Client Client { get; set; } // One Client
  public virtual Phone Phone { get; set; } // One Phone
}
Run Code Online (Sandbox Code Playgroud)

Jay*_*ena 5

您不需要在此处指定电话和客户端之间的关系两次.只使用这样的一个.

modelBuilder.Entity<Client>().HasMany(c => c.Phones).WithMany(i => i.Clients)
                .Map(t => t.MapLeftKey("PhoneID")
                    .MapRightKey("ClientID")
                    .ToTable("ClientPhone"));
Run Code Online (Sandbox Code Playgroud)

您不需要有模型来映射关系表,如"ClientPhone",因为EF会处理它.如果您有遗留数据库,您可以在我的答案中自定义您的映射.正如@Ladislav Mrnka所说的数据库级别中的一对多关系,你不想为这种关系保留一个单独的表.为了那个原因 ,

public class Client
{
  [Key]
  public int ClientID { get; set; }
  public string Name { get; set ;}

  public virtual ICollection<Phone> Phones { get; set; }
}

public class Phone
{
  [Key]
  public int PhoneID { get; set; }
  public string Number { get; set; }

  public virtual Client Client { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这对EF来说已经足够了.它将在Phone表中创建两个带有clientId列的表来保持关系.

问题是你在遗留数据库中有关系的单独表.我认为遗留数据库是为多对多关系定义的.再次思考两次你的域逻辑.

如果你想保持一对多的关系,我认为你可以在域级别定义多对多关系(手机有很多客户端,客户端有很多手机在模型条款中),在你的业务层添加验证保持只有一个客户电话.