Code First EF5:One-to-Zero-One关系不起作用

时间:2013-07-30 22:48:51

标签: c# asp.net-mvc ef-code-first entity-framework-5

似乎没有类似的问题可以解决这个问题。我正在使用Entity Framework 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视图中的关系看起来很好,但是我无法使用Foreign键来使用UserProfile UserId。

我的Fluent API是错误的还是我的模特?请帮忙 - 我真的被卡住了!

1 个答案:

答案 0 :(得分:3)

使用Fluent API进行映射是可以的,但是从模型中删除UserProfile.JoggerIdJogger.UserId属性,它应该可以正常工作。原因是实体框架使用Jogger的主键作为UserProfile的外键,因此您不需要(也不能)具有单独的外键属性。这种一对一的关系称为“Shared Primary Key Association”。

修改

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

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

  • 如果您想在没有UserProfile的情况下插入Jogger,只需将其添加到上下文中:

    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();
    }
    
  • 如果您想在一个步骤中插入UserProfile Jogger

    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(现有Jogger必须为UserProfile):

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