首页 > 解决方案 > 如何从表中获取最后插入的 ID(字符串)

问题描述

我想使用数据库中最后插入的 ID,但该 ID 是字符串格式。有什么办法可以获取最后插入的字符串 ID?

每次我使用

p.UserId = db.AspNetUsers.Max(m => m.Id);

但它返回错误的结果。我认为它是字符串,所以 max 不起作用。谁能建议如何解决这个问题?

表结构:

AspNetUsers表:

CREATE TABLE [dbo].[AspNetUsers] 
(
    [Id]    NVARCHAR(128) NOT NULL,
    [Email] NVARCHAR (256) NULL,
)

患者表:

CREATE TABLE Patient
(
     PatientId INT IDENTITY(1,1) PRIMARY KEY,
     PId AS 'P' + RIGHT('00000' + CAST(PatientId AS NVARCHAR(10)), 10) PERSISTED,
     UserId NVARCHAR(128) FOREIGN KEY REFERENCES AspNetUsers(Id)
)

示例 ID 的格式如下:62d8d072-5261-4aaf-b552-d75453cc3421

这是代码,首先我从 AspNetUsers 表中的视图中获取值,因此它将在表中生成 id,我想将该 Id 用于我的 Patient 表。

[HttpPost]
[ValidateAntiForgeryToken]
[AllowAnonymous]
public async Task<ActionResult> SignUp(Patientview pv)
{
        ClinicDbContext db = new ClinicDbContext();

        if (ModelState.IsValid)
        {
            try
            {
                var user = new ApplicationUser { UserName = pv.Email, Email = pv.Email };
                var result = await UserManager.CreateAsync(user, pv.Password);

                if (result.Succeeded)
                {
                    await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);

                }
                else
                {
                    return View(pv);
                }

                Patient p = new Patient();
                p.FirstName = pv.FirstName;
                p.LastName = pv.LastName;
                p.DateOfBirth = pv.DateOfBirth;
                p.Email = pv.Email;
                p.PhoneNumber = pv.PhoneNumber.ToString();
                p.StreetAddress = pv.StreetAddress.ToString();
                p.City = pv.City;
                p.State = pv.State;
                p.ZipCode = pv.ZipCode;
                p.UserId = db.AspNetUsers.Max(m => m.Id);

                _context.Patients.Add(p);
                _context.SaveChanges();

                return RedirectToAction("Index", "Admin");
            }
            catch (DbEntityValidationException e)
            {
                foreach (var eve in e.EntityValidationErrors)
                {
                    System.Diagnostics.Debug.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
                        eve.Entry.Entity.GetType().Name, eve.Entry.State);
                    foreach (var ve in eve.ValidationErrors)
                    {
                        System.Diagnostics.Debug.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
                            ve.PropertyName, ve.ErrorMessage);
                    }
                }
                throw;
            }
        }
        else
        {
            return View(pv);
        }
}

标签: sql-serverasp.net-mvcentity-framework

解决方案


通常使用 EF,您将使用 FK 映射实体之间的关系,并在保存主记录和关联记录时让 EF 管理 FK 的分配。但是,在您的情况下,这种关系是相对松散耦合的。

是否所有患者记录都将与经过 ASP.Net 身份验证的用户相关联?如果是这样,您可以查看更改 Patient 上的 PK 类型以匹配 ASPNet 表,然后将 Patient 设置为与 ASPNetUser 的一对一关系。

或者,如果患者可以是 ASPNetUser(但也可以是分离的),那么我会考虑将 PatientId 列作为自动递增整数或顺序 GUID(newsequentialId())添加到 ASPNetUser,并将其映射到患者中的 PatientId,作为可选或必需多对一。这绕过了 ASPNetUser 上字符串 PK 的丑陋,并允许您使用更适合您的应用程序的 FK 类型。(整数或 GUID)

您可以使用第三个选项来获取新插入的 PK;PK 只会在 DbContext SaveChanges 之后创建,因此您只需调用 SaveChanges 两次来获取第一个 id:

//...
var user = new ApplicationUser { UserName = pv.Email, Email = pv.Email };
var result = await UserManager.CreateAsync(user, pv.Password);

if (result.Succeeded)
  await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
else
  return View(pv);

_context.SaveChanges();
Patient p = new Patient();
p.PatientId = Guid.Parse(user.UserId); // User ID will be populated after the above SaveChanges call.                
p.FirstName = pv.FirstName;
//...
_context.SaveChanges(); //Save the Patient.

通常虽然这并不理想,因为您可以获得第一个 SaveChanges 成功但第二个失败的情况。这些记录可能应该一起通过,因此这可以通过事务范围或单元或工作(例如 DbContextScope)来实现。

使用事务范围:

using (var tx = new TransactionScope())
{ 
    var user = new ApplicationUser { UserName = pv.Email, Email = pv.Email };
    var result = await UserManager.CreateAsync(user, pv.Password);

    if (result.Succeeded)
      await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
    else
      return View(pv);

    _context.SaveChanges();
    Patient p = new Patient();
    p.PatientId = Guid.Parse(user.UserId); // User ID will be populated after the above SaveChanges call.                
    p.FirstName = pv.FirstName;
    //...
    _context.SaveChanges(); //Save the Patient.

  tx.Complete()
}

但总的来说,映射实体之间的关系会是一个更好的选择,因为这样可以设置 FK 约束来管理诸如级联删除之类的事情。


推荐阅读