【问题标题】:Both One-To-One and One-To-Many relationships in Entity Framework 5 Code FirstEntity Framework 5 Code First 中的一对一和一对多关系
【发布时间】:2012-11-06 19:49:52
【问题描述】:

我尝试了一整天来让它工作。我学到了很多关于 EF 的 Fluent API(例如 this 是一篇很棒的文章),但是我没有成功。

我有三个实体:

public class Address
{
   [Key]
   public virtual int AddressId { get; set; }
   public virtual string AddressString { get; set; }
}
public class User
{
   [Key]
   public virtual int UserId { get; set; }
   public virtual ICollection<Address> Addresses { get; set; }
}
public class House
{
   [Key]
   public virtual int HouseId { get; set; }
   public virtual Address Address { get; set; }
}

并尝试了 HasMany, HasOptional, WithOptional, WithOptionalDependentWithOptionalPrincipial 的所有组合,我可以在

中想到 UserHouse
protected override void OnModelCreating(DbModelBuilder modelBuilder)

我只是无法让它工作。我想应该很清楚,我想要什么。一个用户可能有多个地址(首先我想强制至少一个,但现在如果用户可以有可选的地址,我会很高兴......)而房子只有一个地址 - 这是必需的。如果房子的地址能级联删除就好了。

【问题讨论】:

    标签: c# ef-code-first one-to-many entity-framework-5 one-to-one


    【解决方案1】:

    我相信以下内容应该适合你

    public class Address
    {
        public int AddressId { get; set; }
        public string AddressString { get; set; }
    }
    
    public class User
    {
        public int UserId { get; set; }
        public virtual ICollection<Address> Addresses { get; set; }
    }
    
    public class House
    {
        public int HouseId { get; set; }
        public virtual Address Address { get; set; }
    }
    
    public class TestContext : DbContext
    {
        public DbSet<Address> Addresses { get; set; }
        public DbSet<User> Users { get; set; }
        public DbSet<House> Houses { get; set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<User>().HasMany(u => u.Addresses).WithMany();
            modelBuilder.Entity<House>().HasRequired(h => h.Address).WithOptional().Map(m => m.MapKey("AddressId"));
        }
    }
    

    请注意,通常最好自己指定外键字段,这可以让您日后的生活变得更轻松。如果你这样做,那么你可以选择重写House如下:

    public class House
    {
        public int HouseId { get; set; }
        public int AddressId { get; set; }
        public virtual Address Address { get; set; }
    }
    

    Convention 将连接 AddressId 和 Address。如果您在 House 和 Address 之间有一对一的映射,您还可以将它们链接到它们的主键上:

    public class House
    {
        [ForeignKey("Address")]              
        public int HouseId { get; set; }
        public virtual Address Address { get; set; }
    }
    

    您提到您希望强制执行至少一个地址 - 这对于一对多的关系是不可能的。仅当用户只有一个地址时才能执行此操作,此时您可以在 User 类上添加必需的 AddressId 属性。

    另一条评论 - 您在代码中将所有内容都设为虚拟。您只需要将导航属性设为虚拟即可。

    【讨论】:

    • 好吧,今天睡得更多,我认为我的问题出在初始化程序中,而不是在上下文中……但是,您的回答对我很有价值,希望对其他人也很有价值。
    【解决方案2】:

    这样的事情怎么样:

    House 执行Address

    modelBuilder.Entity<House>().HasRequired(d => d.Address);
    

    UserAddress 之间创建一对多关系:

    modelBuilder.Entity<User>().HasMany(u => u.Addresses).WithMany().Map(x =>
    {
        x.MapLeftKey("UserId");
        x.MapRightKey("AddressId");
        x.ToTable("UserAddress");
    });
    

    这应该做的是创建一个名为UserAddress 的表,将User 映射到Address

    或者,您可以自己为UserAddress 创建一个 POCO 并修改相关表:

    public class UserAddress
    {
        [Key]
        public int UserAddressId { get; set; }
        public User User { get; set; }
        public Address Address { get; set; }
    }
    
    public User
    {
        ...
        public virtual ICollection<UserAddress> UserAddresses { get; set; }
        ...
    }
    
    public Address
    {
        ...
        public virtual ICollection<UserAddress> UserAddresses { get; set; }
        ...
    }
    

    然后,您将需要以下内容以确保 UserAddress 都是必需的:

    modelBuilder.Entity<UserAddress>().HasRequired(u => u.Address);
    modelBuilder.Entity<UserAddress>().HasRequired(u => u.User);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-08
      • 1970-01-01
      • 1970-01-01
      • 2019-07-11
      相关资源
      最近更新 更多