MVC 标识 - INSERT 语句与 FOREIGN KEY 约束冲突
MVC Identity - The INSERT statement conflicted with the FOREIGN KEY constraint
我知道这个问题已经讨论过几次,但这个问题与内置身份模型有关。
我创建了一个名为 "Company" 的自定义模型。注册新用户时,我还想 select 公司名称。
我已将所需的数据添加到 RegisterViewModel 和视图中,并且表单会正常显示。我已经在公司 table 中播种了 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 tables:
AspNetUsers table:
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);
公司table:
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);
有什么想法吗?这里有什么问题?
直觉告诉我它在这一行内(为 clarity/commentary 分解):
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
您只需分配 either/or。在这种情况下,您不需要在填充 ApplicationUser
之前执行查找,只需设置 user.CompanyID = model.CompanyID;
看来我已经找到错误了,感谢您上次的建议!我试图设置外键的值,而不是如果 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.
}
我知道这个问题已经讨论过几次,但这个问题与内置身份模型有关。
我创建了一个名为 "Company" 的自定义模型。注册新用户时,我还想 select 公司名称。
我已将所需的数据添加到 RegisterViewModel 和视图中,并且表单会正常显示。我已经在公司 table 中播种了 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 tables:
AspNetUsers table:
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);
公司table:
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);
有什么想法吗?这里有什么问题?
直觉告诉我它在这一行内(为 clarity/commentary 分解):
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
您只需分配 either/or。在这种情况下,您不需要在填充 ApplicationUser
之前执行查找,只需设置 user.CompanyID = model.CompanyID;
看来我已经找到错误了,感谢您上次的建议!我试图设置外键的值,而不是如果 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.
}