SQL Server & Entity Framework SaveChanges 时唯一约束异常

SQL Server & Entity Framework unique constraint exception when SaveChanges

我有这个数据:

当我将文件上传到 srv 时,有以下代码:

DataContext db = new DataContext();    
[HttpPost]
public ActionResult UploadFiles(HttpPostedFileBase[] files, int? folderid, string description)
{
    foreach (HttpPostedFileBase file in files)
    {
        if (file != null)
        {
            string fileName = Path.GetFileNameWithoutExtension(file.FileName);
            string fileExt = Path.GetExtension(file.FileName)?.Remove(0, 1);

            int? extensionid = db.FileExtensions.FirstOrDefault(m => m.displayname == fileExt)
                ?.file_extensionid;

            if (extensionid == null)
            {
                    CreateExtension(fileExt, out int? extid);
                    extensionid = extid;
            }

            if (CheckFileExist(fileName, fileExt, folderid))
            {
                fileName = fileName + $" ({DateTime.Now.ToString("dd-MM-yy HH:mm:ss")})";
            }

            File dbFile = new File();
            dbFile.folderid = folderid;
            dbFile.displayname = fileName;
            dbFile.file_extensionid = extensionid;
            dbFile.file_content = GetFileBytes(file);
            dbFile.description = description;

            db.Files.Add(dbFile);
            db.SaveChanges();
        }
    }
    return RedirectToAction("Partial_SuccesUploadedToast", "Toast");
}

如果 FileExtension 不在数据库中,我想用这种方法创建它:

 private void CreateExtension(string name, out int? extid)
    {
        if (db.FileExtensions.Any(m => m.displayname == name))
        {
            extid = db.FileExtensions.FirstOrDefault(m => m.displayname == name)?.file_extensionid;
            return;
        }

        FileExtension fileExtension = new FileExtension()
        {
            displayname = name
        };
        db.FileExtensions.Add(fileExtension);
        extid = fileExtension.file_extensionid;
        db.SaveChanges();
    }

因此,当我上传一些具有一个扩展名的文件时,我得到一个异常,即无法添加具有新文件扩展名的实体,因为已经有(唯一约束)。 我能用它做什么?我保存 EXT 和下一个 foreach 循环迭代必须检查 EXT 是否已经存在,idk ...请帮忙!

上下文 类:

    public class File
    {
        [Key]
        [HiddenInput(DisplayValue = false)]
        public int fileid { get; set; }

        [Required(ErrorMessage = "Обязательно укажите название!")]
        [StringLength(200, MinimumLength = 1,
            ErrorMessage = "Название файла должно быть от 1 до 200 символов")]
        public string displayname { get; set; }

        [StringLength(1000,
            ErrorMessage = "Описание файла должно до 1000 символов")]
        public string description { get; set; }

        [HiddenInput(DisplayValue = false)]
        public int? file_extensionid { get; set; }

        [HiddenInput(DisplayValue = false)]
        public int? folderid { get; set; }

        public byte[] file_content { get; set; }

        [ForeignKey("file_extensionid")]
        public FileExtension FileExtension { get; set; }
    
        [ForeignKey("folderid")]
        public Folder Folder { get; set; }

    }



    public class FileExtension
    {
        [Key]
        [HiddenInput(DisplayValue = false)]
        public int file_extensionid { get; set; }

        [Required(ErrorMessage = "Обязательно укажите название расширения!")]
        [StringLength(20, MinimumLength = 1,
            ErrorMessage = "Название расширения должно быть от 1 до 20 символов")]
        public string displayname { get; set; }

        [StringLength(200, MinimumLength = 1,
            ErrorMessage = "Название иконки должно быть от 1 до 200 символов")]
        public string icon_filename { get; set; }
    }

     public class Folder
    {
        [Key]
        [HiddenInput(DisplayValue = false)]
        public int folderid { get; set; } = 0;

        [Required(ErrorMessage = "Обязательно укажите название!")]
        [StringLength(100, MinimumLength = 1,
            ErrorMessage = "Название папки должно быть от 1 до 100 символов")]
        public string displayname { get; set; }

        [HiddenInput(DisplayValue = false)]
        public int? parent_folderid { get; set; }

        //

        [ForeignKey("parent_folderid")]
        public Folder ParentFolder { get; set; }
     }

你有一个错误。您正在尝试在保存更改之前获取扩展 ID。 而且,您正在检查分机两次。为避免这种情况,您可以使用此 func

private int? GetExtensionId(string name)
{
        
var  extItem= db.FileExtensions.FirstOrDefault(m => m.displayname == name);
if(extItem!=null) return extItem.file_extensionid;

 var fileExtension = new FileExtension()
  {
     displayname = name
  };
 db.FileExtensions.Add(fileExtension);
  db.SaveChanges();
  return fileExtension.file_extensionid;
    }

并替换

int? extensionid = db.FileExtensions.FirstOrDefault(m => m.displayname == fileExt)
                ?.file_extensionid;

            if (extensionid == null)
            {
                    CreateExtension(fileExt, out int? extid);
                    extensionid = extid;
            }

有了这个

var extensionid = GetExtensionId(fileExt);

也尝试在 file 和 fileext 之间添加一对多关系

 public class File
    {
       .....
      
        [HiddenInput(DisplayValue = false)]
        public int? file_extensionid { get; set; }

       [ForeignKey(nameof(file_extensionid))]
        [InverseProperty("Files")]
        public FileExtension FileExtension { get; set; }

    public class FileExtension
    {
        .....
       
       [InverseProperty(nameof(File.FileExtension))]
        public virtual ICollection<File> Files { get; set; }
    }

如果仍然无法正常工作,您可能需要重复数据库迁移

这是我的问题的答案

我不知道为什么,但只是出于某种原因才有效,有人可以解释一下吗? 只有储物柜可以帮助...

        private static object locker = new object();
        private int? GetExtensionId(string name)
        {
            int? result = null;
            lock (locker)
            {
                var extItem = db.FileExtensions.FirstOrDefault(m => m.displayname == name);

                if (extItem != null) return extItem.file_extensionid;

                var fileExtension = new FileExtension()
                {
                    displayname = name
                };
                db.FileExtensions.Add(fileExtension);
                db.SaveChanges();
                result = fileExtension.file_extensionid;
            }
            return result;
        }