ASP.NET Identity 2.1和EF 6 - 与其他实体的ApplicationUser关系 [英] ASP.NET Identity 2.1 and EF 6 - ApplicationUser relationships with other entities

查看:354
本文介绍了ASP.NET Identity 2.1和EF 6 - 与其他实体的ApplicationUser关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

似乎找不到这个答案,即使我在做什么似乎对大多数开发人员来说都是常见和重要的。在具有用户帐户的大多数系统中,用户表与数据库中的其他表相关联。这就是我想要的我正在使用MSSQL Express 2012和VS 2013。

Can't seem to find an answer to this one, even though what I'm doing seems like it would be common and important to most developers. In most systems with user accounts, the user table is tied to other tables in the database. That's all I want. I'm using MSSQL Express 2012 and VS 2013.

我有一个类库,我使用代码优先的方法来生成表。我将IdentityModel类从MVC项目移动到这个类库中。一切工作分开 - 我的表生成和工作正常,并且身份表是在我注册新用户时生成的。

I have a class library where I'm using the code-first approach to generate tables. I moved the IdentityModel class from the MVC project to this class library as well. Everything works separately - my tables are generated and work fine, and the Identity tables are generated when I register a new user.

但是,现在我需要我的一个实体/以1-1关系绑定到ApplicationUser的表,但添加如下所示的字段可防止生成Identity表:

However, now I need one of my entities/tables tied to the ApplicationUser in a 1-1 relationship, but adding the field like so prevents the Identity tables from being generated:

public class ApplicationUser : IdentityUser
{
    //***custom field
    public MyPortfolio Portfolio { get; set; }

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        return userIdentity;
    }
}

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("name=MyDataModel", throwIfV1Schema: false)
    {
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

        base.OnModelCreating(modelBuilder);

        //sql output log
        Database.Log = s => Debug.Write(s);
    }
}

...MyPortfolio只是简单的实体:

..."MyPortfolio" is just plain entity:

    public class MyPortfolio
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }

        [StringLength(45, MinimumLength = 3)]
        public string Name { get; set; }

        public Boolean IsMaster { get; set; }

        //public ApplicationUser User { get; set; } //threw exception!
    }

我不太了解身份,但是读过Migrations可能成为答案。如果可能,我宁愿避免任何进一步的复杂性。真的有必要吗?我正处于早期发展阶段,并将再次删除/重新创建表格。

I don't know too much about Identity, but have read that Migrations might be the answer. I'd rather avoid any further complexity if possible. Will that really be necessary? I am in early development and will be dropping/re-creating the tables many more times.

更新1:

好的,我添加了下面描述的adricadar。这是发生了什么...

OK, I added everything like adricadar described below. Here's what happened...

添加迁移时,我必须从包管理器控制台的默认项目下拉列表中选择我的类库。在启用迁移时,出现以下错误:

When adding migrations I had to select my class library from the "Default project" dropdown in the Package Manager Console. When doing Enable-Migrations, I got the following error:


在程序集MyProject.Data中找到多个上下文类型。
要启用MyProject.Models.ApplicationDbContext的迁移,请使用
启用迁移-ContextTypeName
MyProject.Models.ApplicationDbContext。要启用
'MyProject.Data.MyDataModel'的迁移,请使用启用迁移-ContextTypeName
MyProject.Data.MyDataModel。

More than one context type was found in the assembly 'MyProject.Data'. To enable migrations for 'MyProject.Models.ApplicationDbContext', use Enable-Migrations -ContextTypeName MyProject.Models.ApplicationDbContext. To enable migrations for 'MyProject.Data.MyDataModel', use Enable-Migrations -ContextTypeName MyProject.Data.MyDataModel.

...所以我做了以下:

...so I did the following:


启用迁移-ContextTypeName
MyProject.Models.ApplicationDbContext

Enable-Migrations -ContextTypeName MyProject.Models.ApplicationDbContext

...正如预期的那样,为AspNetUser *表创建了Configuration类和InitialCreate类。

...which as expected, created the Configuration class and an "InitialCreate" class for the AspNetUser* tables.

然后,我运行了添加迁移UserPortofolioRelation,它用Up()和Down()生成DbMigration类。 Up和Down都定义了MyDataModel中定义的所有表。我现在看到Up()中MyPortfolio和AspNetUsers之间的关系:

I then ran "Add-Migration UserPortofolioRelation", which generated the DbMigration class with Up() and Down(). Up and Down both define all of the tables I've defined in MyDataModel. I now see the relationship between MyPortfolio and AspNetUsers in Up():

        CreateTable(
                "dbo.MyPortfolio",
                c => new
                        {
                            Id = c.Int(nullable: false, identity: true),
                            Name = c.String(maxLength: 45),
                            IsMaster = c.Boolean(nullable: false),
                            UserId = c.String(nullable: false, maxLength: 128),
                        })
                .PrimaryKey(t => t.Id)
                .ForeignKey("dbo.AspNetUsers", t => t.UserId)
                .Index(t => t.UserId);

当我运行Update-Database时,我收到以下错误:

When I run Update-Database, I get the following error:


应用显式迁移:
[201504141316068_UserPortofolioRelation]。应用显式迁移:
201504141316068_UserPortofolioRelation。
System.Data.SqlClient.SqlException(0x80131904):数据库中已经有一个名为MyPortfolio的
对象。

Applying explicit migrations: [201504141316068_UserPortofolioRelation]. Applying explicit migration: 201504141316068_UserPortofolioRelation. System.Data.SqlClient.SqlException (0x80131904): There is already an object named 'MyPortfolio' in the database.

我对Migrations知识的程度是这个基础教程:

The extent of my knowledge of Migrations is this basic tutorial:

https://msdn.microsoft.com/en-us/data/jj591621.aspx

这适用于我,只有新的字段在生成的迁移代码中定义,而不是删除和创建所有表的命令。

This worked for me, and only the new fields were defined in the generated migrations code, not commands to drop and create all the tables.

更新2 :

我遵循本教程,这似乎在尝试使用多个数据上下文中的迁移时,更清楚地解释了一些问题:

I followed this tutorial, which seemed to explain things a little more clearly when trying to work with migrations on multiple data contexts:

http://www.dotnet-tricks.com/Tutorial/entityframew ork / 2VOa140214-Entity-Framework-6-Code-First-Migrations-with-Multiple-Data-Contexts.html

我运行了这个命令: / p>

I ran this command:


启用迁移-ContextTypeName
MyProject.Models.ApplicationDbContext

Enable-Migrations -ContextTypeName MyProject.Models.ApplicationDbContext

创建了以下配置:

internal sealed class Configuration : DbMigrationsConfiguration<MyProject.Models.ApplicationDbContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
    }

    protected override void Seed(MyProject.Models.ApplicationDbContext context)
    {
    }
}

...看起来不错然后我运行这个:

...looking good. Then I ran this:


添加迁移 - 配置MyProject.Data.Migrations.Configuration
MigrationIdentity

Add-Migration -Configuration MyProject.Data.Migrations.Configuration MigrationIdentity

...生成此文件:

namespace MyProject.Data.Migrations
{
    using System;
    using System.Data.Entity.Migrations;

    public partial class MigrationIdentity : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                    "dbo.MyPortfolio",
                    c => new
                            {
                                Id = c.Int(nullable: false, identity: true),
                                Name = c.String(maxLength: 45),
                                IsMaster = c.Boolean(nullable: false),
                                UserId = c.String(nullable: false, maxLength: 128),
                            })
                    .PrimaryKey(t => t.Id)
                    .ForeignKey("dbo.AspNetUsers", t => t.UserId)
                    .Index(t => t.UserId);

            ...my other non-identity entities...

            CreateTable(
                    "dbo.AspNetUsers",
                    c => new
                            {
                                Id = c.String(nullable: false, maxLength: 128),
                                Email = c.String(maxLength: 256),
                                EmailConfirmed = c.Boolean(nullable: false),
                                PasswordHash = c.String(),
                                SecurityStamp = c.String(),
                                PhoneNumber = c.String(),
                                PhoneNumberConfirmed = c.Boolean(nullable: false),
                                TwoFactorEnabled = c.Boolean(nullable: false),
                                LockoutEndDateUtc = c.DateTime(),
                                LockoutEnabled = c.Boolean(nullable: false),
                                AccessFailedCount = c.Int(nullable: false),
                                UserName = c.String(nullable: false, maxLength: 256),
                            })
                    .PrimaryKey(t => t.Id)
                    .Index(t => t.UserName, unique: true, name: "UserNameIndex");

            ...other Identity entities/tables...

        }

        public override void Down()
        {
            ...everything you'd expect...
        }
    }
}

真棒!一个文件中的所有表/实体!所以我运行它:

Awesome! All tables/entities in one file! So I ran it:


更新 - 数据库 - 配置MyProject.Data.Migrations.Configuration
-Verbose

Update-Database -Configuration MyProject.Data.Migrations.Configuration -Verbose

...和bam!它在MyPortfolio表上使用UserId FK生成所有表。所有这一切似乎都与世界很好。没有什么可以阻止我现在!然后我运行它,得到这个例外:

...and bam! It generated all the tables with the UserId FK on the MyPortfolio table. All seems to be great with the world. Nothing can stop me now! Then I ran it and got this exception:


在模型生成期间检测到一个或多个验证错误:

One or more validation errors were detected during model generation:

System.Data.Entity.ModelConfiguration.ModelValidationException

System.Data.Entity.ModelConfiguration.ModelValidationException

MyProject.Data.IdentityUserLogin::EntityType'IdentityUserLogin'有
无键定义。定义此EntityType的键。
MyProject.Data.IdentityUserRole::EntityType'IdentityUserRole'有
无键定义。定义此EntityType的键。
IdentityUserLogins:EntityType:EntitySet'IdentityUserLogins'是基于没有定义键的IdentityUserLogin类型的

IdentityUserRoles:EntityType:EntitySet'IdentityUserRoles'基于
类型'IdentityUserRole',没有定义键。

MyProject.Data.IdentityUserLogin: : EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType. MyProject.Data.IdentityUserRole: : EntityType 'IdentityUserRole' has no key defined. Define the key for this EntityType. IdentityUserLogins: EntityType: EntitySet 'IdentityUserLogins' is based on type 'IdentityUserLogin' that has no keys defined. IdentityUserRoles: EntityType: EntitySet 'IdentityUserRoles' is based on type 'IdentityUserRole' that has no keys defined.

一个快速的Google自然而然地将我带回了Stack Exchange: EntityType'IdentityUserLogin'没有定义键。定义此EntityType的密钥

A quick Google brought me back to Stack Exchange, naturally: EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType

接受的答案概述了一大堆新的可能的角度,以尝试让其正常工作。这让我回到我原来的问题。我可以这样做而不使用迁移。有可能吗?随着这个复杂程度的提高,我正在认真地辩论滚动我自己的认证,如果没有。我已经花费了大量的时间尝试简单地将代码优先实体绑定到身份用户。每个新门都会再出现两次。它似乎不值得...但也许他们会在下一个版本中清理一下。

The accepted answer outlines a whole slew of new possible angles to play, to try and get this to work right. This brings me back to my original question. Can I do this without migrations. Is that possible, in any way? With the level of complexity this comes with, I'm seriously debating "rolling my own" authentication, if not. I've already spent an exorbitant amount of time trying to simply tie a code-first entity to the Identity user. Each new door presents two more to go through. It just doesn't seem worth it...but maybe they'll clean this up a bit in the next release.

推荐答案

您可以在 OnModelCreating 中指定关系。

尝试使用一个 DbContext 每个数据库。通常,您为不同的数据库使不同 DbContexts ,而不是相同。

Try to use one DbContext per database. Usually you make different DbContexts for different databases, not for same.

将所有实体移动到 ApplicationDbContext 中,并按照以下说明操作。

Move all your entities in ApplicationDbContext and follow the instruction below.

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("name=MyDataModel", throwIfV1Schema: false)
    {
    }

    public DbSet<MyPortfolio> Portfolios { get; set; }
    // The rest of the entities
    // goes here

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

        modelBuilder.Entity<MyPortfolio>()
            .HasRequired(m => m.User  )
            .WithOptional(m => m.Portfolio )
            .Map(m => { m.MapKey("UserId"); });

        base.OnModelCreating(modelBuilder);

        //sql output log
        Database.Log = s => Debug.Write(s);
    }

}

比你更新数据库随着迁移,这很容易。在Visual Studio中打开包管理器控制台,然后按顺序输入此命令。

Than you have to update your database, with migration, it's very easy. Open Package Manager Console in Visual Studio and enter this commands in order.

Enable-Migration
Add-Migration UserPortofolioRelation`
Update-Database

这篇关于ASP.NET Identity 2.1和EF 6 - 与其他实体的ApplicationUser关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆