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

时间:2017-10-22 17:08:52

标签: c# entity-framework asp.net-core jqgrid

过去曾有过不同形式的问题,但我仍然无法让它发挥作用。

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

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

  

实体类型'CoList'上的属性'AutoId'是键的一部分,因此无法修改或标记为已修改。

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

我的模型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;
    }

点击“保存”后,代码会在“重试保存操作”中崩溃。

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);
            }
        }
    });

});

我已经阅读了这些答案,但他们没有帮助我,或者我误解了一些事情。

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

The property 'name' is part of the object's key information and cannot be modified. Entity Framework

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(我将在稍后的视图中使用额外的表):

    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:错误:保存更改时数据库中发生异常。   Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException:数据库操作预计会影响1行但实际上影响了0行。自加载实体以来,数据可能已被修改或删除。有关理解和处理乐观并发异常的信息,请参阅http://go.microsoft.com/fwlink/?LinkId=527962。      at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ThrowAggregateUpdateConcurrencyException(Int32 commandIndex,Int32 expectedRowsAffected,Int32 rowsAffected)      在Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.d__6.MoveNext()   ---从抛出异常的先前位置开始的堆栈跟踪结束---

有趣的是,当我从VS为我的数据库中的任何表生成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);
    }

仍然没有快乐

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

1 个答案:

答案 0 :(得分:1)

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

如果prmNames由于某些原因(Guriddo jqGrid或代码中的错误)不起作用,但您看到具有正确值的id属性被发送到服务器,那么您可以添加int id EditCoList参数coList.AutoId id以及_context.Update(coList);之前基于object SingleKotlin { // some members of SingleKotlin @JvmStatic val x = 42 } 分配SingleKotlin.getX(); @Modifying(clearAutomatically = true) @Query(value = "UPDATE stories s " + "SET rank = :reorderPosition" + " WHERE id = :selectedStory ;" + "UPDATE stories s " + "SET rank = rank+1" + " WHERE rank >= :reorderPosition " + "AND id <> :selectedStory ;" +"SELECT id " + "FROM stories s " + "WHERE s.epic_Id = :epicId " + "ORDER BY rank", nativeQuery = true) List<Integer> reorder(@Param("selectedStory") int selectedStory, @Param("reorderPosition") int reorderPosition,@Param("epicId") int epicId);