代码优先EF5:一对零或一关系不起作用

本文关键字:关系 不起作用 代码 EF5 | 更新日期: 2023-09-27 18:25:38

类似的问题似乎都无法解决这个问题。我使用实体框架5,MVC 4,.NET 4.5作为我的web应用程序,使用VS 2012设计。

我有两个班,应该是亲子关系。

[Table("UserProfile")]
public class UserProfile
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }
    // Other stuff
    public int? JoggerId { get; set; }
    public virtual Jogger Jogger{ get; set; }
}

 public class Jogger
{
    [Key]
    public int JoggerId { get; set; }
    [Required, ForeignKey("UserId")]
    public int UserId { get; set; }
    public virtual UserProfile UserProfile { get; set; }
}

使用Fluent API:

 protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<UserProfile>()
            .HasOptional(x => x.Jogger)
            .WithRequired(c => c.UserProfile)
            .WillCascadeOnDelete(true);
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        base.OnModelCreating(modelBuilder);
    }

用户可以是慢跑者,但也可以不是慢跑者,即一个用户到零或一个慢跑者。在EF Powertools edmx视图中,关系看起来很好,但我无法获得外键来使用UserProfile UserId。

我的Fluent API是错的还是我的模型?请帮帮我,我真的被卡住了!

代码优先EF5:一对零或一关系不起作用

使用Fluent API进行映射是可以的,但从模型中删除UserProfile.JoggerIdJogger.UserId属性,它应该可以工作。原因是Entity Framework使用Jogger的主键作为UserProfile的外键,因此您不需要(也不能)具有单独的外键属性。这种一对一的关系被称为"共享主键关联"。

编辑

请记住,Jogger的主键(作为关系的依赖项)是而不是在数据库中自动生成的,只有UserProfile的主键是自动生成的(作为关系主体)。

UserProfileJogger或两者都插入数据库的方式如下:

  • 如果您想插入一个没有JoggerUserProfile,只需将其添加到上下文中即可:

    using (var context = new MyContext())
    {
        var newUserProfile = new UserProfile();
        // no key needs to be supplied, the DB will take care
        context.UserProfiles.Add(newUserProfile);
        context.SaveChanges();
    }
    
  • 如果您想在一个步骤中插入带有JoggerUserProfile

    using (var context = new MyContext())
    {
        var newUserProfile = new UserProfile { Jogger = new Jogger() };
        // no key needs to be supplied, neither for UserProfile
        // nor for Jogger, the DB will take care
        context.UserProfiles.Add(newUserProfile);
        context.SaveChanges();
    }
    
  • 如果要插入Jogger(对于现有的UserProfile,它必须是Jogger):

    using (var context = new MyContext())
    {
        var newJogger = new Jogger { JoggerId = someExistingUserProfileId };
        // a valid key needs to be supplied, otherwise you would violate a FK
        // constraint in the database
        context.Joggers.Add(newJogger);
        context.SaveChanges();
    }
    

编辑2

对于您的用例,如果您没有直接可用的UserId,而是Name(作为已验证用户),则必须首先从数据库加载密钥或UserProfile

// we are in an ASP.NET MVC controller action here
using (var context = new MyContext())
{
    string userName = User.Identity.Name;
    int? userId = context.UserProfiles
        .Where(u => u.Name == userName)
        .Select(u => (int?)u.UserId)
        .SingleOrDefault();
    if (userId.HasValue)
    {
        var newJogger = new Jogger { JoggerId = userId.Value };
        context.Joggers.Add(newJogger);
        context.SaveChanges();
    }
}

或者加载UserProfile也可以:

using (var context = new MyContext())
{
    string userName = User.Identity.Name;
    UserProfile userProfile = context.UserProfiles
        .Where(u => u.Name == userName)
        .SingleOrDefault();
    if (userProfile != null)
    {
        userProfile.Jogger = new Jogger();
        // I believe you don't need to set the JoggerId key now,
        // I'm not sure though
        context.SaveChanges();
        // Change tracking recognizes the new Jogger
        // no context.Joggers.Add is required
    }
}