【问题标题】:MVC Identity - The INSERT statement conflicted with the FOREIGN KEY constraintMVC Identity - INSERT 语句与 FOREIGN KEY 约束冲突
【发布时间】:2016-03-28 18:58:46
【问题描述】:

我知道这个问题已经讨论过几次了,但这个问题与内置的身份模型有关。

我创建了一个名为“Company”的自定义模型。注册新用户时,我还想选择公司名称。

我已将所需的数据添加到 RegisterViewModel 中,视图和表单将按应有的方式显示。我已经在 Company 表中播种了 2 家公司,因此该值不应为空。

public class RegisterViewModel
{        
   ... Removed some irrelevant code ...

    [Required(ErrorMessage = "You must select a company name.")]
    [Display(Name = "Company")]
    public int CompanyID { get; set; }
    public virtual Company ApplicationUser_Company { get; set; }

当我想插入一个新用户时出现以下错误:

The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.AspNetUsers_dbo.Companies_CompanyID". The conflict occurred in database "aspnet-ProjectMed-20160327120257", table "dbo.Companies", column 'CompanyID'.
The statement has been terminated. 

检查帐户控制器我没有发现任何问题:

    // GET: /Account/Register
    [AllowAnonymous]
    public ActionResult Register()
    {
        ViewBag.CompanyID = new SelectList(db.Companies, "CompanyID", "Company_Name");
        return View();
    }

    //
    // POST: /Account/Register
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Register(RegisterViewModel model)
    {
        if (ModelState.IsValid)
        {
            var user = new ApplicationUser { UserName = model.Email, Email = model.Email, ApplicationUser_FirstName = model.ApplicationUser_FirstName, ApplicationUser_LastName = model.ApplicationUser_LastName, ApplicationUser_Company = model.ApplicationUser_Company };

                var result = await UserManager.CreateAsync(user, model.Password); <<<---- This is where the error occurs <<<---
                if (result.Succeeded)
                {
                    await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);

                    return RedirectToAction("Index", "Home");
                }
                AddErrors(result);

        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

我也在复制 SQL 表:

AspNetUsers 表:

CREATE TABLE [dbo].[AspNetUsers] (
    [Id]                        NVARCHAR (128) NOT NULL,
    [ApplicationUser_FirstName] NVARCHAR (50)  NOT NULL,
    [ApplicationUser_LastName]  NVARCHAR (50)  NOT NULL,
    [CompanyID]                 INT            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_dbo.AspNetUsers_dbo.Companies_CompanyID] FOREIGN KEY ([CompanyID]) REFERENCES [dbo].[Companies] ([CompanyID]) ON DELETE CASCADE
);

GO
CREATE NONCLUSTERED INDEX [IX_CompanyID]
    ON [dbo].[AspNetUsers]([CompanyID] ASC);

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

公司表:

CREATE TABLE [dbo].[Companies] (
    [CompanyID]          INT            IDENTITY (1, 1) NOT NULL,
    [Company_Name]       NVARCHAR (50)  NOT NULL,
    [Company_Code]       NVARCHAR (9)   NOT NULL,
    [Company_Address1]   NVARCHAR (100) NOT NULL,
    [Company_Address2]   NVARCHAR (100) NULL,
    [Company_PostalCode] NVARCHAR (15)  NOT NULL,
    [Company_City]       NVARCHAR (50)  NOT NULL,
    [CountryID]          INT            NOT NULL,
    [Company_CLOG]       BIT            NOT NULL,
    [Company_SubAgent]   BIT            NOT NULL,
    CONSTRAINT [PK_dbo.Companies] PRIMARY KEY CLUSTERED ([CompanyID] ASC),
    CONSTRAINT [FK_dbo.Companies_dbo.Countries_CountryID] FOREIGN KEY ([CountryID]) REFERENCES [dbo].[Countries] ([CountryID]) ON DELETE CASCADE
);


GO
CREATE UNIQUE NONCLUSTERED INDEX [IX_Company_Code]
    ON [dbo].[Companies]([Company_Code] ASC);


GO
CREATE NONCLUSTERED INDEX [IX_CountryID]
    ON [dbo].[Companies]([CountryID] ASC);

有什么想法吗?这里有什么问题?

【问题讨论】:

  • 那么 model.ApplicationUser_Company 的值在 UserManager.CreateAsync 之前是否正确?

标签: sql-server asp.net-mvc asp.net-identity


【解决方案1】:

Gut 告诉我它在这一行之内(为了清晰/评论而分解):

var user = new ApplicationUser
{
  UserName = model.Email,
  Email = model.Email,
  ApplicationUser_FirstName = model.ApplicationUser_FirstName,
  ApplicationUser_LastName = model.ApplicationUser_LastName,
  ApplicationUser_Company = model.ApplicationUser_Company      // <--
};

基本上,在表单操作之间传递实体引用时,您希望引用 ID(因为整个实体不会通过网络传输,也不应出于安全目的(输入错误、黑客攻击等))。

您的 ViewModel(在这种情况下,RegisterViewModel 应该只有 CompanyID(这是 Company 实体的 PK)。然后应该使用它来填充新用户 ApplicationUser (user)通过执行查找然后分配给user。例如

[HttpPost]
public async Task<ActionResult> Register(RegisterViewModel model)
{
  // verify the models' valid
  if (ModelState.IsValid)
  {
    // Perform a lookup to retrieve the selected company
    var company = db.COmpanies.SingleOrDefault(x => x.CompanyID == model.CompanyID);
    if (company != null) // Found it
    {
      // No go on to establish an application user
      var user = new ApplicationUser {
        /* ... */,
        ApplicationUser_Company = company // entity we retrieved
      };

      //
      // SignInManager yatta yata
      //
    }
  }
  return View(model); // Uh-oh fallback.
}

但请注意,如果您的 ApplicationUser 实体有两个属性(大多数都有),一个用于 ID,一个用于外部关系;例如

public int CompanyID { get; set; } // ID property
[ForeignKey("CompanyID")]
public virtual Company Company { get; set; } // entity property

您只需要指定一个/或。在这种情况下,您无需在填充ApplicationUser 之前执行查找,只需设置user.CompanyID = model.CompanyID;

【讨论】:

  • 谢谢布拉德!我添加了查找“var company = db.Companies ....”,似乎我们离解开这个谜更近了一步。但是现在我收到错误“一个实体对象不能被多个 IEntityChangeTracker 实例引用。”。有什么建议吗?如果这是一个新手问题,对不起...... :)
【解决方案2】:

由于您的最后建议,我似乎找到了错误!我试图设置外键的值而不是 ID...

对我有用的代码:

[HttpPost]
public async Task<ActionResult> Register(RegisterViewModel model)
{
  // verify the models' valid
  if (ModelState.IsValid)
  {
      var user = new ApplicationUser {
        /* ... */,
        CompanyID = model.CompanyID // entity we retrieved
      };

      //
      // SignInManager yatta yata
      //
  }
  return View(model); // Uh-oh fallback.
}

【讨论】:

    猜你喜欢
    • 2017-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-27
    相关资源
    最近更新 更多