实体类型上的 属性 是键的一部分,因此无法修改或标记为已修改。 EF 核心 Dotnet 核心

The property on entity type is part of a key and so cannot be modified or marked as modified. EF Core Dotnet Core

过去有人以不同的形式询问过这个问题,但我仍然无法让它工作。

我正在 dotnet core / ef core 中构建一个站点,在一个页面上我想使用 jqGrid 轻松编辑一个 table 将经常更改的页面。 Table被称为CoList(公司列表)

我已经可以添加新行并删除它们,但是当我尝试编辑行时出现此错误:

The property 'AutoId' on entity type 'CoList' is part of a key and so cannot be modified or marked as modified.

我首先创建了数据库,因为它在我开始在这个新网站上工作之前在其他地方使用过。

我的模型CoList.cs:

    public partial class CoList
{
    public int AutoId { get; set; }
    public string CompanyName { get; set; }
    public string CoLevel { get; set; }
    public string CoCode { get; set; }
}

数据库上下文文件

            modelBuilder.Entity<CoList>(entity =>
        {

            entity.HasKey(e => e.AutoId)
                .HasName("PK_CoList");

            entity.HasIndex(e => e.AutoId).IsUnique();

            entity.Property(e => e.AutoId).HasColumnName("AutoID");

            entity.Property(e => e.CoCode)
                .IsRequired()
                .HasColumnType("varchar(50)");

            entity.Property(e => e.CoLevel)
                .IsRequired()
                .HasColumnType("varchar(50)");

            entity.Property(e => e.CompanyName)
                .IsRequired()
                .HasColumnType("varchar(50)");
        });

在编辑控制器中我有:

public string EditCoList(int? Id, [Bind(include: "CompanyName, CoLevel, CoCode")] CoList coList)
    {

        FPSDemoContext db = _context;
        string msg;

        try
        {

            if (ModelState.IsValid)
            {
                db.Entry(coList).State = EntityState.Modified;
                db.SaveChanges();
                msg = "Saved";
            }
            else
            {
                msg = "Did not validate";
            }


        }
        catch (DbUpdateConcurrencyException ex)
        {
            foreach (var entry in ex.Entries)
            {
                if (entry.Entity is CoList)
                {

                    var databaseEntity = db.CoList.AsNoTracking().Single(p => p.AutoId == Id);
                    var databaseEntry = db.Entry(databaseEntity);

                    foreach (var property in entry.Metadata.GetProperties())
                    {
                        var proposedValue = entry.Property(property.Name).CurrentValue;
                        var originalValue = entry.Property(property.Name).OriginalValue;
                        var databaseValue = databaseEntry.Property(property.Name).CurrentValue;


                        entry.Property(property.Name).CurrentValue = proposedValue;


                        entry.Property(property.Name).OriginalValue = databaseEntry.Property(property.Name).CurrentValue;
                    }

                }
                else
                {
                    msg = "Error occured:" + ex.Message;
                    throw new NotSupportedException("Concurrency conflict  " + entry.Metadata.Name);

                }
            }

            // Retry the save operation
            db.SaveChanges();

            msg = "Saved";
        }


        return msg;
    }

点击保存后,代码在 'Retry Save operation' 上崩溃。

jqGrid代码:

$(function () {
$("#jqGrid").jqGrid({
    regional: 'en',
    url: "/SiteOptions/GetCoList",
    datatype: 'json',
    mtype: 'Get',
    colNames: ['Id', 'Company Name', 'Company Level', 'Company Code'],
    colModel: [
        { key: true, name: 'autoId', index: 'autoId', editable: false },
        { key: false, name: 'companyName', index: 'companyName', editable: true },
        { key: false, name: 'coLevel', index: 'coLevel', editable: true },
        { key: false, name: 'coCode', index: 'coCode', editable: true }],
    pager: jQuery('#jqControls'),
    rowNum: 10,
    rowList: [10, 20, 30, 40, 50],
    height: '100%',
    viewrecords: true,
    caption: 'Company List - Grid',
    emptyrecords: 'No Companies to display',
    jsonReader: {
        root: "rows",
        page: "page",
        total: "total",
        records: "records",
        repeatitems: false,
        Id: "0"
    },
    autowidth: true,
    multiselect: false
}).navGrid('#jqControls', { edit: true, add: true, del: true, search: false, refresh: true },
    {
        zIndex: 100,
        url: '/SiteOptions/EditCoList',
        closeOnEscape: true,
        closeAfterEdit: true,
        recreateForm: true,
        afterComplete: function (response) {
            if (response.responseText) {
                alert(response.responseText);
            }
        }
    },
    {
        zIndex: 100,
        url: "/SiteOptions/CreateCoList",
        closeOnEscape: true,
        closeAfterAdd: true,
        afterComplete: function (response) {
            if (response.responseText) {
                alert(response.responseText);
            }
        }
    },
    {
        zIndex: 100,
        url: "/SiteOptions/DeleteCoList",
        closeOnEscape: true,
        closeAfterDelete: true,
        recreateForm: true,
        msg: "Are you sure you want to delete this row? ",
        afterComplete: function (response) {
            if (response.responseText) {
                alert(response.responseText);
            }
        }
    });

});

我已经阅读了那些答案,但它们对我没有帮助,或者我误解了什么。

https://github.com/aspnet/EntityFrameworkCore/issues/4560

编辑 #2

根据评论,我将编辑方法更改为:

public async Task<IActionResult> EditCoList(int Id, CoList coList)
    {

        string msg;
        msg = "Model state is not valid";

        if (Id != coList.AutoId)
        {
            msg = "Not Found";
        }

        if (ModelState.IsValid)
        {
            try
            {
                _context.Update(coList);
                await _context.SaveChangesAsync();
                msg = "Saved";
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!CoListExists(coList.AutoId))
                {
                    msg = "Concurrency Exception - Not Found";
                }
                else
                {
                    msg = "Error";
                    throw;
                }
            }
        }

        return Content(msg);
    }

        private bool CoListExists(int? id)
    {
        return _context.CoList.Any(e => e.AutoId == id);
    }

我也在使用 viewmodel(有额外的 table 我稍后会需要在那个视图上):

    namespace ASPNET_Core_1_0.Models.SiteOptionsViewModels
{
    public class SiteOptionsViewModel
    {

        public IEnumerable<ASPNET_Core_1_0.Models.SiteOptions> SiteOptions { get; set; }
        public IEnumerable<ASPNET_Core_1_0.Models.CoList> CoList { get; set; }


       public ASPNET_Core_1_0.Models.SiteOptions AutoId { get; set; }
       public ASPNET_Core_1_0.Models.SiteOptions CurrentMonth { get; set; }
       public ASPNET_Core_1_0.Models.SiteOptions CurrentYear { get; set; }
       public ASPNET_Core_1_0.Models.SiteOptions SelectedCompanyId { get; set; }



       public ASPNET_Core_1_0.Models.CoList CompanyName { get; set; }
       public ASPNET_Core_1_0.Models.CoList CoLevel { get; set; }
       public ASPNET_Core_1_0.Models.CoList CoCode { get; set; }

    }
}

在控制器中我这样调用视图:

        public async Task<IActionResult> Companylist()
    {
        ViewData["SubTitle"] = "Company List";
        ViewData["Message"] = "Edit company list";

        var model = new SiteOptionsViewModel
        {
            SiteOptions = await _context.SiteOptions.ToListAsync(),
            CoList = await _context.CoList.ToListAsync()
        };

        return View(model);
    }

我仍然遇到并发错误:

Microsoft.EntityFrameworkCore.DbContext:Error: An exception occurred in the database while saving changes. Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions. at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ThrowAggregateUpdateConcurrencyException(Int32 commandIndex, Int32 expectedRowsAffected, Int32 rowsAffected) at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.d__6.MoveNext() --- End of stack trace from previous location where exception was thrown ---

有趣的是,当我从 VS 为我的数据库中的任何 table 生成 CRUD 控制器时,它总是有效,在编辑或保存编辑时完全没有问题。我按照生成的代码创建了自己的代码,但仍然出现并发错误。

编辑#3

添加了 prmNames 的 jqGrid js 脚本:{ id: "AutoId" }(根据 Oleg 评论),

$(function () {
$("#jqGrid").jqGrid({
    regional: 'en',
    prmNames: { id: "AutoId" },
    url: "/SiteOptions/GetCoList",
    datatype: 'json',
    mtype: 'Get',
    colNames: ['Id', 'Company Name', 'Company Level', 'Company Code'],
    colModel: [
        { key: true, name: 'autoId', index: 'autoId', editable: false },
        { key: false, name: 'companyName', index: 'companyName', editable: true },
        { key: false, name: 'coLevel', index: 'coLevel', editable: true },
        { key: false, name: 'coCode', index: 'coCode', editable: true }],
    pager: jQuery('#jqControls'),
    rowNum: 10,
    rowList: [10, 20, 30, 40, 50],
    height: '100%',
    viewrecords: true,
    caption: 'Company List - Grid',
    emptyrecords: 'No Companies to display',
    jsonReader: {
        root: "rows",
        page: "page",
        total: "total",
        records: "records",
        repeatitems: false,
        Id: "0"
    },
    autowidth: true,
    multiselect: false
}).navGrid('#jqControls', { edit: true, add: true, del: true, search: false, refresh: true },
    {
        zIndex: 100,
        url: '/SiteOptions/EditCoList',
        closeOnEscape: true,
        closeAfterEdit: true,
        recreateForm: true,
        afterComplete: function (response) {
            if (response.responseText) {
                alert(response.responseText);
            }
        }
    },
    {
        zIndex: 100,
        url: "/SiteOptions/CreateCoList",
        closeOnEscape: true,
        closeAfterAdd: true,
        afterComplete: function (response) {
            if (response.responseText) {
                alert(response.responseText);
            }
        }
    },
    {
        zIndex: 100,
        url: "/SiteOptions/DeleteCoList",
        closeOnEscape: true,
        closeAfterDelete: true,
        recreateForm: true,
        msg: "Are you sure you want to delete this row? ",
        afterComplete: function (response) {
            if (response.responseText) {
                alert(response.responseText);
            }
        }
    });

});

方法(根据 Oleg 评论):

 public async Task<IActionResult> EditCoList(CoList coList)
    {

        string msg;
        msg = "Model state is not valid";

        /*if (Id != coList.AutoId)
        {
            msg = "Not Found";
        }*/

        if (ModelState.IsValid)
        {
            try
            {
                _context.Update(coList);
                await _context.SaveChangesAsync();
                msg = "Saved";
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!CoListExists(coList.AutoId))
                {
                    msg = "Concurrency Exception - Not Found";
                }
                else
                {
                    msg = "Error";
                    throw;
                }
            }
        }

        return Content(msg);
    }

还是不开心

有人可以告诉我我做错了什么吗?我还在学习,所以它可能很简单。如果可能的话,你们中的任何人都可以告诉我正确的解决方案吗?

我建议您添加 prmNames: { id: "autoId" } 选项以通知 jqGrid 在发送编辑结果时使用 autoId 属性 而不是 id 属性到服务器。

如果 prmNames 由于某些原因(Guriddo jqGrid 或您的代码中的错误)而无法工作,但您看到 id 属性 具有正确的值被发送到服务器然后您可以将 int id 参数添加到 EditCoList 操作并根据 id 行 [=19] 之前分配 coList.AutoId =]