【问题标题】:Foreign Key Issue preventing me from tying an existing table into ASP.NET Identity 2.0 (Azure Servers)外键问题阻止我将现有表绑定到 ASP.NET Identity 2.0(Azure 服务器)
【发布时间】:2025-12-04 00:00:01
【问题描述】:

原来的错误现在已经解决了,尽管我离实现所需的功能还差得远。查看最终更新

本文的第一部分是我上周在 Reddit(/sql 和 /csharp)上发布的原始问题。底部是此后的一些更新信息

我正在开发一个使用 Azure SQL 数据库的 webapp(C#、MVC 5)。我还在实现内置的 ASP.NET Identity 2.0 系统(我确定这就是我的问题所在)。

可能是因为我选择了一个设置,凭证系统坚持使用本地数据库,而不是我的基于云的数据库(一旦我的笔记本电脑关闭,这将毫无用处)。

我已将所有表迁移到我的 azure sql db,设置了一个新的连接字符串并将 IdentityModel 指向新连接,而不是默认连接(是的,它与常规的 azure 连接不同,后者使用实体框架而不是 SqlClient)

当我尝试注册本地数据库时,一切正常。当我将其更改为引用 azure 数据库时,出现此错误:

 SqlException (0x80131904): The INSERT statement conflicted with the FOREIGN KEY constraint "FK_AspNetUsers_ToTable". The conflict occurred in database "PhoenixMachineTracking", table "dbo.Distributor", column 'Dist_ID'. The statement has been terminated. 

这是发生错误的地方:

 Line 153:            {
 Line 154:                var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
 **Line 155:                var result = await UserManager.CreateAsync(user, model.Password);**
 Line 156:                if (result.Succeeded)
 Line 157:                {

我已经更改了一些东西,但收效甚微(尽管这是最新的错误;我正在取得进展,哈哈),此时我不确定问题是否在我的连接字符串中 (我不这么认为) 几乎肯定不会 - 查看最后的更新、我的 c# 代码(我找不到任何看起来错误的东西)或我的表(看起来我的所有外键都存在且正确) )

我做错了什么?下面是表创建脚本,以及我的“类”(不确定当 VS 从数据库为您构建它们时它们是否被调用)

分销商表(将登录的用户)

 CREATE TABLE [dbo].[Distributor] (  
[Dist_ID]      NVARCHAR (128) NOT NULL,  
[Dist_Name]    NVARCHAR (256) NULL,  
[Dist_Address] VARCHAR (50)   NULL,  
[Dist_City]    VARCHAR (50)   NULL,  
[Dist_State]   VARCHAR (50)   NULL,  
[Dist_Zip]     VARCHAR (50)   NULL,  
[Dist_Phone]   VARCHAR (50)   NULL,  
[Dist_Fax]     VARCHAR (50)   NULL,  
[Dist_Contact] VARCHAR (50)   NULL,  
[Dist_Email]   VARCHAR (50)   NULL,  
CONSTRAINT [PK_dbo.Distributor] PRIMARY KEY CLUSTERED ([Dist_ID] ASC));

Visual Studio 生成的 ASP.NET 表作为 ASP 标识的一部分

 CREATE TABLE [dbo].[AspNetUsers] (
[Id]                   NVARCHAR (128) NOT NULL,
[Email]                NVARCHAR (256) NULL,
[EmailConfirmed]       BIT            NOT NULL,
[PasswordHash]         NVARCHAR (MAX) NULL,
[SecurityStamp]        NVARCHAR (MAX) NULL,
[PhoneNumber]          NVARCHAR (MAX) NULL,
[PhoneNumberConfirmed] BIT            NOT NULL,
[TwoFactorEnabled]     BIT            NOT NULL,
[LockoutEndDateUtc]    DATETIME       NULL,
[LockoutEnabled]       BIT            NOT NULL,
[AccessFailedCount]    INT            NOT NULL,
[UserName]             NVARCHAR (256) NOT NULL,
CONSTRAINT [PK_dbo.AspNetUsers] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_AspNetUsers_ToTable] FOREIGN KEY ([Id]) REFERENCES [dbo].[Distributor] ([Dist_ID]));


 GO
 CREATE UNIQUE NONCLUSTERED INDEX [UserNameIndex]
ON [dbo].[AspNetUsers]([UserName] ASC);

ASP.NET 用户类 - 作为 ASP.NET 标识的一部分生成

namespace PhoenixProductTracking.db
 {
using System;
using System.Collections.Generic;

public partial class AspNetUsers
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public AspNetUsers()
    {
        this.AspNetUserClaims = new HashSet<AspNetUserClaims>();
        this.AspNetUserLogins = new HashSet<AspNetUserLogins>();
        this.AspNetRoles = new HashSet<AspNetRoles>();

    }

    public string Id { get; set; }
    public string Email { get; set; }
    public bool EmailConfirmed { get; set; }
    public string PasswordHash { get; set; }
    public string SecurityStamp { get; set; }
    public string PhoneNumber { get; set; }
    public bool PhoneNumberConfirmed { get; set; }
    public bool TwoFactorEnabled { get; set; }
    public Nullable<System.DateTime> LockoutEndDateUtc { get; set; }
    public bool LockoutEnabled { get; set; }
    public int AccessFailedCount { get; set; }
    public string UserName { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<AspNetUserClaims> AspNetUserClaims { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<AspNetUserLogins> AspNetUserLogins { get; set; }
    public virtual Distributor Distributor { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<AspNetRoles> AspNetRoles { get; set; }

}}

分销商类 - 从数据库生成

 namespace PhoenixProductTracking.db
 {
using System;
using System.Collections.Generic;

public partial class Distributor
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Distributor()
    {
        this.Machine = new HashSet<Machine>();
    }

    public string Dist_ID { get; set; }
    public string Dist_Name { get; set; }
    public string Dist_Address { get; set; }
    public string Dist_City { get; set; }
    public string Dist_State { get; set; }
    public string Dist_Zip { get; set; }
    public string Dist_Phone { get; set; }
    public string Dist_Fax { get; set; }
    public string Dist_Contact { get; set; }
    public string Dist_Email { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Machine> Machine { get; set; }
    public virtual AspNetUsers AspNetUsers { get; set; }
}}

身份模型类(更改默认连接的地方)

 namespace PhoenixProductTracking.Models
 {
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        return userIdentity;
    }
}

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("PhoenixLogInConnection", throwIfV1Schema: false)
    {             **THIS IS WHERE THE CONNECTION WAS CHANGED FROM "DEFAULTCONNECTION"**
    }

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

Web.Config - 我的连接字符串被定义的地方

默认(本地)连接

  <add name="DefaultConnection" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-PhoenixProductTracking-20160118123425.mdf;Initial Catalog=aspnet-PhoenixProductTracking-20160118123425;Integrated Security=True" providerName="System.Data.SqlClient" />

Azure 实体连接

<add name="PhoenixMachineTrackingEntities" connectionString="metadata=res://*/db.PhoenixAzureDb.csdl|res://*/db.PhoenixAzureDb.ssdl|res://*/db.PhoenixAzureDb.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=*****.database.windows.net;initial catalog=PhoenixMachineTracking;persist security info=True;user id=******4;password=*****;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />

用于登录的 Azure 连接

<add name="PhoenixLogInConnection" connectionString="Server=******.database.windows.net,1433;Database=PhoenixMachineTracking;User ID=*****;Password=******;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;" providerName="System.Data.SqlClient"/>

更新:

自从那篇文章发布以来,我尝试了一些方法,取得了中等的成功。我可以确认,当我从 Distributor 表中解开 AspNetUsers 表时,“注册”函数有效(这是在任何新 MVC 项目的第一页上看到的内置注册函数。我只更改了第一页[暂时] 显示我想要的数据,因为我需要让登录系统正常工作,然后才能继续前进)。一旦我将它们连接在一起,它就会停止工作。这仍然使用 Azure 连接字符串,而不是 DefaultConnection,这意味着我可以将连接排除为问题。

我已尝试手动将分发服务器放入分发服务器表中,然后针对该用户名进行注册,以消除当 AspNetUser 表尝试为其设置外键时分发服务器表中不存在数据而导致问题的可能性。当我这样做时,我得到了同样的错误。

模型和“类”(由 Visual Studio 从我现有的数据库结构自动创建。它显示在我的解决方案资源管理器中的 edmx 下,但它们实际上可能不被称为类......我在这里有点缺乏经验) 看起来都是正确的,甚至包含(我认为是)对它们相关的任何表/类的正确引用。

我目前正在深入研究 ASP.NET 身份文件,试图了解它是如何与数据库通信的。希望这可以告诉我我的问题。目前运气不佳。我也在尝试查看是否可以在 edmx 图上创建关系,然后使用它来更新表,以便它自己创建关系(消除由于我缺乏经验而导致的错误)

我不会说我在我的头上,但我肯定取决于我的眼球,我冷需要一些帮助。我会继续研究(我不是那种坐下来等待答案的人)如果我弄明白了就更新,但现在已经有几天了,我需要解决这个问题,这样我才能继续完成这个项目(一个刚毕业的小型企业开发人员,所以我的支持网络相当有限)

提前感谢您的帮助

更新 2:

感谢NPC。 (s)他指出我正在关联两个主键,这是一种不寻常的方法,这可能会导致问题。我在我的 Distributor 表中创建了一个名为“AspNetUserID”的字段,并将其与来自 AspNetUsers 的 ID 字段相关联,这为我清除了错误。

此时,我需要弄清楚如何在代码中自动创建该关联(目前是复制粘贴),方法是创建所需的分发器,或者与现有分发器关联。如果有人想指出我在代码中发生这种情况的方向,那会很有帮助。不然我就随便找找找了

【问题讨论】:

  • 嗨大卫,我想知道你为什么尝试连接 2 个主键。通常,当您想将某些内容链接到另一个表时,您会在表 AspNetUsers 中创建一个新列“DistributorId” - 因此,当尝试将两个(通常自动生成的)主键设置为外键时,Azure 数据库可能更加严格
  • 我在教程中得到了非常明确的指示,不要更改身份表,因为这会导致实现出现问题。我可能处理不正确,但我看不到另一种方法。我的最终目标是根据登录的分销商限制显示的数据,但是如果没有将分销商绑定到 AspNetUsers,我想不出一个建立这种关联的好方法(尽管我可能想对了,但处理错了)。分发者表和 AspNetUser 表充当内置 auth 系统和现有 db 之间的桥梁
  • 在aspnet-users 和distributors 之间创建链接最简单的方法是直接将Distributor 的属性添加到ApplicationUser。如果您不想接触aspnetuser,您也许可以使用自己的配置文件属性(msdn.microsoft.com/en-us/library/d8b58y5d(v=vs.100).aspx)-您可以将distributorId作为字符串存储为配置文件属性并自己进行真正的链接... GetDistributorById 或类似的东西-但是这不是一个安全的参考:/
  • 添加公共分销商 LinkedDistributor {get; set;} 到 ApplicationUser 确实是最方便的方法。我希望其他人有更好的主意
  • 你的第一篇文章给了我一个想法,它(至少)消除了错误。你是对的,我从不同的表中耦合主键很奇怪,所以我在我的 Distributor 表中添加了一个列 AspNetUserID 并在它和来自 AspNetUsers 的主键之间创建了一个关联。这消除了错误的问题。我仍然需要通过从 AspNetUsers 复制和粘贴 ID 来关联它们,但是当我尝试登录时它不会抱怨。需要更多的工作,但错误消失了,谢谢

标签: c# asp.net azure asp.net-identity-2 asp.net-mvc-5.2


【解决方案1】:

您需要删除 AspNetUsers 部分类。我假设您使用某种逆向工程从数据库创建模型。一旦您声明了ApplicationUser : IdentityUser 并通过ApplicationDbContext : IdentityDbContext&lt;ApplicationUser&gt; 将它们绑定到您的上下文,就不需要身份类(AspNetUsers、AspNetRoles...)。它由 Identity EntityFramwork 负责。您要添加到用户的任何其他属性都应添加到ApplicationUser 类。

【讨论】:

  • “我假设您使用某种逆向工程从数据库创建模型。”我猜,有点。我在我的 MVC 项目中包含了一个现有的数据库,并且 VS2015 自动生成了模型,所以 I 没有对其进行逆向工程,但这似乎是一个过程。至于声明 IdentityUser 类,我没有。在创建具有单用户授权的 MVC 5 项目时,它自己创建了所有这些类。当我应该能够将我的用户表(分发器)绑定到现有的身份验证系统时,我宁愿不拆卸和重新设计身份验证系统
  • 您正在使用数据库优先方法和 .edmx。在那种情况下,我不会更改生成的代码。我建议您研究 Code First 方法,因为它与 Identity 和 EntityFarmework 配合得更好。它还使您可以更好地控制您的实体,并且您可以进行使用身份所需的必要修改
  • 这听起来像是“从头开始,尽可能多地移植”。那是对的吗?我很想避免这种情况,但如果这就是它所需要的,我可以做到。我应该如何以一种导致我尽可能少地重新创建的方式来解决这个问题(我可以从当前项目中复制什么)。我从来没有处理过代码优先的方法(这将如何影响我对现有数据库的使用,其中已经有相当数量的数据)
  • 您不必更改数据库中的任何内容。您可以使用EntityFramework PowerTools 之类的工具,一键从数据库中创建所有编码实体。特别是如果你打算使用 asp.net Identity 的话,这是值得的。