C# 如何在使用实体框架将数据保存到MVC中时,根据表的最大标识键生成唯一的编号?

C# 如何在使用实体框架将数据保存到MVC中时,根据表的最大标识键生成唯一的编号?,c#,.net,sql-server,asp.net-mvc,entity-framework,C#,.net,Sql Server,Asp.net Mvc,Entity Framework,我必须缩短以下代码 我需要在列中生成并保存一个唯一的参考号,如R00001、R00002、R00003,等等。这里的1、2和3基于标识键值 为此,我编写了两次db.SaveChanges()。首先,我保存数据并选择保存的数据,然后通过生成唯一键来更新它。是否可以生成该密钥并在保存时立即传递 因此,在保存和更新数据后,我不需要再次调用db.SaveChanges()两次来选择数据。这是我的MVC控制器(MVC操作)代码 我想减少此代码,因为我正在保存需要以R00001.pdf,R00002.pdf

我必须缩短以下代码

我需要在列中生成并保存一个唯一的参考号,如
R00001
R00002
R00003
,等等。这里的1、2和3基于标识键值

为此,我编写了两次
db.SaveChanges()
。首先,我保存数据并选择保存的数据,然后通过生成唯一键来更新它。是否可以生成该密钥并在保存时立即传递

因此,在保存和更新数据后,我不需要再次调用
db.SaveChanges()
两次来选择数据。这是我的MVC控制器(MVC操作)代码

我想减少此代码,因为我正在保存需要以
R00001.pdf
R00002.pdf
R00003.pdf
等格式保存的文件

以下是根据唯一参考号重命名文件名的文件保存代码

if (files != null)
{
  foreach (HttpPostedFileBase file in files)
  {
    if (file != null)
    {
      //To generate the file name of the rate contract.
      var fileName = "RC" + string.Format("{0:D5}", objRC.RatecontractId);
      var extension = Path.GetExtension(file.FileName);
      fileName = fileName + extension;

      string path = string.Format("~/Documents/PDF/{0}", fileName);

       if (System.IO.File.Exists(Server.MapPath(path)))
          System.IO.File.Delete(Server.MapPath(path));
       file.SaveAs(Server.MapPath(path));

       RateTable resultForfiles = (from rc in dbTender.RateTables where 
       rc.RatecontractId == objRC.RatecontractId select rc).SingleOrDefault();
       if (resultForfiles != null && (extension.ToLower() == "pdf" || extension.ToLower() == ".pdf"))
       {
          resultForfiles.PdfFilePath = fileName;
       }
       if (resultForfiles != null && extension.ToLower() != "pdf" && extension.ToLower() != ".pdf")
       {
          resultForfiles.WordExcelFilePath = fileName;
       }
       dbTender.SaveChanges(); //Third thime calling `SaveChanges()`
     }
   }
}

第二次调用数据库的问题似乎可以通过插入后的数据库触发器解决

所有其他代码选项都无法解决第二次调用的问题,例如使用存储过程或执行SQL查询

我的建议是将工作分成由触发器和C#代码完成的数据库级别,以解决文件保存问题


插入触发器后:

作为选项,您可以创建标识列和计算列,在计算列中,根据标识列计算所需的值。例如:

CREATE TABLE [dbo].[Table1](
    [Id] INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    [Name] NVARCHAR(50) NOT NULL,
    [Code]  AS (('R'+ REPLICATE('0',(5) - LEN(CONVERT([NVARCHAR](50),[Id])))) +
        CONVERT([NVARCHAR](50),[Id]))
)
public ActionResult Download(Guid id)
{
    var file = Server.MapPath($"~/Content/uploads/{id}.pdf";
    return File(file, "application/pdf", "something.pdf");
}
然后,当您使用EF或类似这样的查询插入到表中时:

INSERT INTO [dbo].[Table1]([Name]) VALUES (N'Something')
结果是:

| Id   | Name           | Code              |
.............................................
| 1    | Something      | R00001            |
重要提示

在选择任何解决方案之前,无论是计算列、序列还是触发器, 确保您需要在数据库中存储这样的计算代码我认为您不需要在数据库端生成和存储参考代码,只需使用 实体的键作为参考号/外键 需要逻辑或物理关系

使用标识列:您可以定义标识
Id
列。然后在数据库中插入
yourEnitty
之后,在
SaveChanges()
之后,
yourEntity.Id
将包含新插入的标识值,您不需要对数据库进行额外调用。然后您可以使用相同的id作为引用(例如作为文件名)

使用Guid列:您可以定义Guid
Id
列。然后在数据库中插入
yourEnitty
之前,将
Guid.NewId()
分配到
Id
列,然后可以使用相同的Guid作为引用(例如作为文件名)

考虑以下几点:

  • 存储中文件的名称或密钥以及数据库中实体的密钥是您的区域,最终用户与此无关
  • 您可能希望使用Azure Blob、SQL数据库、文件系统等存储,在这些存储技术中,您可以为文件使用不同的密钥/名称
  • 最终用户可以说的唯一一件事是,“我希望看到具有友好名称的文件链接”,或者“我希望在下载文件时有一个友好的名称”,并且在网格中或下载时,您很容易提供这样的友好名称
我的建议是使用一个键(比如guid键)来存储和检索文件。然后,在下载操作中,您可以轻松地使用不同的名称发送文件进行下载,例如:

CREATE TABLE [dbo].[Table1](
    [Id] INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    [Name] NVARCHAR(50) NOT NULL,
    [Code]  AS (('R'+ REPLICATE('0',(5) - LEN(CONVERT([NVARCHAR](50),[Id])))) +
        CONVERT([NVARCHAR](50),[Id]))
)
public ActionResult Download(Guid id)
{
    var file = Server.MapPath($"~/Content/uploads/{id}.pdf";
    return File(file, "application/pdf", "something.pdf");
}

如果您使用的是Microsoft SQL Server,那么这是序列的完美工作

序列在微软世界已经存在了一段时间

它们被设计为生成可以是整个数据库全局的顺序值

非常容易创建和消费

请查看文档:

然后,您可以使用序列的输出来“组合”字符串,甚至只使用该值在insert语句中设置主键或唯一键列

序列是“标识”列的完美替代

它们符合ANSI/ISO SQL标准

以下是有关如何使用序列的一些信息甚至示例的链接:

在insert语句期间,序列也可以用作列中的默认值约束


警告:据我所知,此功能在SQL Server 2012及更高版本中可用。

这似乎是一个触发器的工作。@Steve我知道这一点,并通过多次编写代码在C代码中完成,我想知道还有其他方法可以做到这一点吗?谢谢。我更喜欢使用计算列而不是触发器。但这是需要在数据库上完成的事情,我对实体框架了解不够,无法告诉您是否可以直接从c#执行。所有实体框架解决方案都需要对数据库进行第二次调用,无论您是使用代码、执行SQL语句还是调用存储过程。为此,数据库级别的触发器将是最佳实践。见插入后的触发:我将把所有想法写在一个答案中,以便将来检索。在这种情况下,序列只给出标识。虽然我已经在中提到了序列,但我想说,要走的路是我在我答案的注释部分所分享的。@RezaAghaei我不同意。标识是自动生成的自动设置值……虽然可以从代码中调用一个序列来“合成”一个新值,例如使用squence输出作为后缀的字符串,如“R”+sequence输出。@RezaAghaei还使用GUID列来表示PK,出于性能原因,使用唯一键或任何其他类型的索引。@JonathanAlfaro我的重点不是实现唯一性,而是如何在调用SaveChanges()之前或同时在调用SaveChanges()方法时获取标识键值