实体框架:一对一的关系

时间:2016-11-16 14:56:40

标签: c# asp.net-mvc entity-framework

我有

public class MyUser : IdentityUser<int,MyLogin,MyUserRole,MyUserClaim>
{
     public virtual MyUserProfile Profile { get; set; }
}

public class MyUserProfile
{
     public int Id { get; set; }
     public string FirstName { get; set; }
     public string LastName { get; set; }
}

我的IdentityUser实现有INT PK。我希望在MyUser中有一个导航属性,而在另一侧则没有。我更喜欢数据注释。是否可以使用IdentityUser PK进行导航? (EF v 6.1.3)

UPD#1。 依赖类型 - MyUserProfile。并且它不必包含MyUser类型的导航属性。

3 个答案:

答案 0 :(得分:2)

我问你为什么要这样做,一个更好的解决办法可能就是把它放在一张桌子上,因为它会更快,除非它们都是大型实体而且配置文件是可选的(但是即使这样,你也可以有一个单独的专栏,说明额外的数据是否可用。

由于您似乎要求1:0..1关系,您可以按如下方式实现它。我知道你想要数据注释,但我真的建议在这里明确*,这样你的模型的任何改变都不会导致潜在的无意识的连锁反应。

public class MyUser : IdentityUser<int,MyLogin,MyUserRole,MyUserClaim>
{
     public virtual MyUserProfile Profile { get; set; }
}

public class MyUserProfile
{
     public int Id { get; set; }
     public string FirstName { get; set; }
     public string LastName { get; set; }

     public MyUser User { get; set; }
}

DbContext上,使用以下内容覆盖OnModelCreating

modelBuilder.Entity<MyUserProfile>()
            .HasRequired(m => m.User)
            .WithOptional(m => m.Profile);

**完全披露:我也总是喜欢数据注释而不是Fluent配置语法,但我迄今为止还没有避免它,并且它确实没有任何缺点。对于像这样基本的东西,你不希望它受到属性的微小变化的影响。

这会生成以下架构,以便在我们预期的两个表之间同步ID时保持精益:

        CreateTable(
            "dbo.MyUsers",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    Test = c.String(),
                })
            .PrimaryKey(t => t.Id);

        CreateTable(
            "dbo.MyUserProfiles",
            c => new
                {
                    Id = c.Int(nullable: false),
                    Test = c.String(),
                })
            .PrimaryKey(t => t.Id)
            .ForeignKey("dbo.MyUsers", t => t.Id)
            .Index(t => t.Id);

正如@ grek40所提到的,可以通过翻转关系的流畅配置在另一端没有导航属性来完成(请参阅注释以获取更多信息),请参阅grek40对该选项的回答。

答案 1 :(得分:2)

我想提一下我的测试与@RudiVisser关于创建的数据库的答案的细微差别。

public class MyUser
{
    public int Id { get; set; }

    public virtual MyUserProfile Profile { get; set; }
}

public class MyUserProfile
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}


class MyContext : DbContext
{
    public DbSet<MyUser> Users { get; set; }
    public DbSet<MyUserProfile> Profiles { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<MyUser>()
            .HasOptional(x => x.Profile)
            .WithRequired();
    }
}

生成的迁移

public override void Up()
{
    CreateTable(
        "dbo.MyUserProfiles",
        c => new
            {
                Id = c.Int(nullable: false),
                FirstName = c.String(),
                LastName = c.String(),
            })
        .PrimaryKey(t => t.Id)
        .ForeignKey("dbo.MyUsers", t => t.Id)
        .Index(t => t.Id);

    CreateTable(
        "dbo.MyUsers",
        c => new
            {
                Id = c.Int(nullable: false, identity: true),
            })
        .PrimaryKey(t => t.Id);
}

与他的回答相反,我没有观察到创建单独的MyUser_Id外键。 MyUserProfiles.Id已正确配置为主键和外键。因此,任何想要使用这种配置的人都应该尝试一下,但要仔细观察生成的迁移代码。

我的工具集:Visual Studio 2013,EntityFramework 6.1.3 nuget package。

答案 2 :(得分:0)

我确定你是否想要那个,但你可以&#34;拆分表&#34;。 换句话说,对两个实体使用相同的表。

像这样:

[Table("MyUser ")]
public class MyUser : IdentityUser<int,MyLogin,MyUserRole,MyUserClaim>
{
     public virtual MyUserProfile Profile { get; set; }
}

[Table("MyUser ")]
public class MyUserProfile
{
     [Key]
     public int Id { get; set; }

     public string FirstName { get; set; }
     public string LastName { get; set; }
}