【问题标题】:asp.net ef 7 Inserting when IDENTITY_INSERT is set to OFF problemsasp.net ef 7 IDENTITY_INSERT设置为OFF时插入问题
【发布时间】:2016-01-19 18:46:33
【问题描述】:

当我尝试保存到我的数据库时出现错误

SqlException:当 IDENTITY_INSERT 设置为 OFF 时,无法在表“照片”中插入标识列的显式值。

我在 Visual Studio 2015 上使用 asp.net 5 MVC 6 和 EF 7 类似的问题还有很多。大多数都有 asp.net 5 MVC 6 或 EF 7 不支持的解决方案(有人说使用数据注释可以解决 EF 6 中的问题)。其他的都没有工作。我尽量不问,除非万不得已。

我的设计是每个用户会有很多文件夹,一个文件夹会有很多照片。

我将public ICollection<UserFolder> UserFolders { get; set; } 添加到ApplicationUser

模型:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations.Schema;

namespace FamPhotos.Models
{
    public class UserFolder
    {
        public int ID { get; set; }
        public string Name { get; set; }

        public ICollection<Photo> Photo { get; set; }

        public string ApplicationUserId { get; set; }
        public virtual ApplicationUser ApplicationUser { get; set; }
    }

    public class Photo
    {
        public int ID { get; set; }
        public string Description { get; set; }
        public DateTime UploadDate { get; set; }
        public string Url { get; set; }

        public int UserFolderId { get; set; }
        public UserFolder UserFolder { get; set; }

    }
}

控制器方法

// POST: Photos/Create
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create(Photo photo, IFormFile files, int id)
    {
        if (files == null)
        {
            ModelState.AddModelError(string.Empty, "Please select a file to upload.");
        }
        else if (ModelState.IsValid)
        {
            photo.UploadDate = DateTime.Now;
            photo.UserFolderId = id;

            var folderName = _context.UserFolder.Where(q => q.ID == id).Single().Name; 

            //TODO:  Check for image types
            var fileName = photo.ID.ToString() + ContentDispositionHeaderValue.Parse(files.ContentDisposition).FileName.Trim('"');
            var filePath = Path.Combine(_applicationEnvironment.ApplicationBasePath, "Photos", User.GetUserName(), folderName, fileName);
            await files.SaveAsAsync(filePath);

            photo.UserFolder = _context.UserFolder.Where(q => q.ID == id).Single();
            photo.Url = "~/Photos/" + fileName;

            _context.Add(photo);
            _context.SaveChanges();


            return RedirectToAction("Index");
        }
        return View(photo);
    }

观点:

    @model FamPhotos.Models.Photo

@{
    ViewData["Title"] = "Create";
}

<h2>Create</h2>

<form asp-action="Create" asp-controller="Photos" method="post" enctype="multipart/form-data">
    <div class="form-horizontal">
        <h4>Photo</h4>
        <hr />
        <div asp-validation-summary="ValidationSummary.ModelOnly" class="text-danger"></div>
        <input type="file" name="files" />
        <label asp-for="Description" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <input asp-for="Description" class="form-control" />
            <span asp-validation-for="Description" class="text-danger" />
        </div>
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Create" class="btn btn-default" />
        </div>
    </div>
</form>

<div>
    <a asp-action="Index">Back to List</a>
</div>

@section Scripts {
    <script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
    <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
}

我的 DbContext:

   namespace FamPhotos.Models
{
    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        protected override void OnModelCreating(ModelBuilder builder)
        {
            builder.Entity<UserFolder>()
                .HasMany(q => q.Photo)
                .WithOne(c => c.UserFolder)
                .HasForeignKey(c => c.UserFolderId);



            base.OnModelCreating(builder);
            // Customize the ASP.NET Identity model and override the defaults if needed.
            // For example, you can rename the ASP.NET Identity table names and more.
            // Add your customizations after calling base.OnModelCreating(builder);
        }
        public DbSet<Photo> Photo { get; set; }
        public DbSet<ApplicationUser> ApplicationUser { get; set; }
        public DbSet<UserFolder> UserFolder { get; set; }
    }
}

谢谢。

【问题讨论】:

  • 您对错误感到困惑。 IDENTITY_INSERT OFF 表示数据库不允许您插入和标识值(这是当您有标识列时的正常情况)。在以下情况下,您可以打开 IDENTITY_INSERT,例如,恢复一堆包含身份键的记录,并且您希望在更新中覆盖键值或在插入中指定它。 ON 表示允许您插入身份。
  • 您的 OnModelCreating 不完整。看看这个问题的公认答案。 stackoverflow.com/questions/15258571/…

标签: c# asp.net-mvc entity-framework visual-studio-2015


【解决方案1】:

如果您不希望数据库生成 ID,则应在模型上使用 DatabaseGenerated 属性,如

public class MyModel
{
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int ID {get;set;}
    ...
}

EF7 实际上支持该属性。

https://docs.microsoft.com/en-us/ef/core/modeling/generated-properties

【讨论】:

  • 是否有另一种方法可以在表的播种期间临时允许写入 PK 身份?
  • @AdamCox - 在种子操作期间,您可以发出命令context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT &lt;Table&gt; ON");,然后确保在完成后发出 OFF 命令(记住“ON”表示您可以插入,“OFF”表示你不能)
  • 我确实尝试过,但无法在我的 EF Core 2.0.2 DbContext 上找到 Database.ExecuteSqlCommand 的方法。我错过了一些扩展吗?
  • @AdamCox - 数据库是一种属性,而不是一种方法。 docs.microsoft.com/en-us/dotnet/api/… - ExecuteSqlCommand 是 RelationalDatabaseFacadeExtensions 类中的扩展方法。
【解决方案2】:

如果要向数据库中插入主键,则数据库列上没有标识。

错误消息表明您正在尝试选择一个主键,而数据库想要为您选择一个。

要么关闭标识,要么让数据库选择主键。

【讨论】:

  • 将 ID 更改为 PhotoID 和 UserFolderID。我以为我已经读过任何一个都会做我想做的事。
猜你喜欢
  • 2011-10-02
  • 2010-10-01
  • 2013-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-27
相关资源
最近更新 更多