主键 mvc 实体框架模型错误

Posted

技术标签:

【中文标题】主键 mvc 实体框架模型错误【英文标题】:primary key mvc entitityframework model error 【发布时间】:2014-08-06 07:42:20 【问题描述】:

这把我逼疯了。

我有一个包含几列和一个主键(bigint,非空)的表

我让 VS 创建了它的模型

public long ParcelRangeID  get; set; 
..
..

然后我创建控制器和视图。当我使用 Create View 创建新记录时,在 db.SaveChanges 上麻烦开始了:(我已将该字段包含在我的视图中为 HiddenFor)

没有进一步的变化;我得到一个必需的 ID 丢失错误。 (同样当我使用 DataAnnotations [Key][DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)][HiddenInput(DisplayValue = false)] 当我使用 [Bind(Exclude="ParcelRangeID")] 时,我得到了 DbUpdateConcurrencyException。

如何插入新记录并自动生成所需的 ID 而不会出错?

编辑

这是控制器代码:

    [HttpPost]
            [ValidateAntiForgeryToken]
            public ActionResult Create(ParcelRange parcelrange)
            
                if (ModelState.IsValid)
                
                    db.ParcelRange.Add(parcelrange);
                    db.SaveChanges();
                    return RedirectToAction("Index");
                

                return View(parcelrange);
            

还有模特:

 public partial class ParcelRange
    
        public ParcelRange()
        
            this.PickupAddressID = -1;
            this.OrganizationID = -1;
            this.DepotID = -1;
            this.IsVTG = 0;
            this.IsInternal = 0;
            this.IsInterCompany = 0;
            this.UpdateCount = 0;
            this.IsActive = 1;
            this.Modified = DateTime.Now.Date;
            this.Created = DateTime.Now.Date;
            this.ValidFrom = DateTime.Now.Date;
            this.ValidTo = DateTime.MaxValue;
        

        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        [Key]
        [HiddenInput(DisplayValue = false)]
        public long ParcelRangeID  get; set; 
        public long NdswCustomerID  get; set; 
        public long PickupAddressID  get; set; 
        public long OrganizationID  get; set; 
        public long DepotID  get; set; 
        public string ParcelRangePrefix  get; set; 
        public string ParcelNumberStart  get; set; 
        public string ParcelNumberEnd  get; set; 
        public byte IsVTG  get; set; 
        public byte IsInternal  get; set; 
        public byte IsInterCompany  get; set; 
        public byte[] RowVer  get; set; 
        public System.DateTime Created  get; set; 
        public System.DateTime Modified  get; set; 
        public int UpdateCount  get; set; 
        public System.DateTime ValidFrom  get; set; 
        public System.DateTime ValidTo  get; set; 
        public byte IsActive  get; set; 
    

编辑 (2)

最后是自动生成的(默认)视图

@model MvcApplication1.ParcelRange

@
    ViewBag.Title = "Create";


<h2>Create</h2>

@using (html.BeginForm()) 
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)
    @Html.HiddenFor(model => model.ParcelRangeID)

    <fieldset>
        <legend>ParcelRange</legend>

        <div class="editor-label">

            @Html.LabelFor(model => model.NdswCustomerID)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.NdswCustomerID)
            @Html.ValidationMessageFor(model => model.NdswCustomerID)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.PickupAddressID)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.PickupAddressID)
            @Html.ValidationMessageFor(model => model.PickupAddressID)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.OrganizationID)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.OrganizationID)
            @Html.ValidationMessageFor(model => model.OrganizationID)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.DepotID)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.DepotID)
            @Html.ValidationMessageFor(model => model.DepotID)
        </div>

@*        <div class="editor-label">
            @Html.LabelFor(model => model.ParcelRangePrefix)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ParcelRangePrefix)
            @Html.ValidationMessageFor(model => model.ParcelRangePrefix)
        </div>*@

        <div class="editor-label">
            @Html.LabelFor(model => model.ParcelNumberStart)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ParcelNumberStart)
            @Html.ValidationMessageFor(model => model.ParcelNumberStart)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ParcelNumberEnd)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ParcelNumberEnd)
            @Html.ValidationMessageFor(model => model.ParcelNumberEnd)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.IsVTG)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.IsVTG)
            @Html.ValidationMessageFor(model => model.IsVTG)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.IsInternal)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.IsInternal)
            @Html.ValidationMessageFor(model => model.IsInternal)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.IsInterCompany)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.IsInterCompany)
            @Html.ValidationMessageFor(model => model.IsInterCompany)
        </div>

@*        <div class="editor-label">
            @Html.LabelFor(model => model.Created)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Created)
            @Html.ValidationMessageFor(model => model.Created)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Modified)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Modified)
            @Html.ValidationMessageFor(model => model.Modified)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.UpdateCount)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.UpdateCount)
            @Html.ValidationMessageFor(model => model.UpdateCount)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ValidFrom)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ValidFrom)
            @Html.ValidationMessageFor(model => model.ValidFrom)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ValidTo)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ValidTo)
            @Html.ValidationMessageFor(model => model.ValidTo)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.IsActive)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.IsActive)
            @Html.ValidationMessageFor(model => model.IsActive)
        </div>*@

        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>


<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts 
    @Scripts.Render("~/bundles/jqueryval")

编辑 (3) 表的数据库脚本:

USE [DPDCDB_ODS]
GO

/****** Object:  Table [dbo].[ParcelRange]    Script Date: 16-6-2014 15:50:40 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[ParcelRange](
    [ParcelRangeID] [bigint] IDENTITY(1,1) NOT NULL,
    [NdswCustomerID] [bigint] NOT NULL,
    [PickupAddressID] [bigint] NOT NULL,
    [OrganizationID] [bigint] NOT NULL,
    [DepotID] [bigint] NOT NULL,
    [ParcelRangePrefix]  AS (left([ParcelNumberStart],(4))),
    [ParcelNumberStart] [nvarchar](50) NOT NULL,
    [ParcelNumberEnd] [nvarchar](50) NOT NULL,
    [IsVTG] [tinyint] NOT NULL,
    [IsInternal] [tinyint] NOT NULL,
    [IsInterCompany] [tinyint] NOT NULL,
    [RowVer] [timestamp] NOT NULL,
    [Created] [datetime] NOT NULL,
    [Modified] [datetime] NOT NULL,
    [UpdateCount] [int] NOT NULL,
    [ValidFrom] [date] NOT NULL,
    [ValidTo] [date] NOT NULL,
    [IsActive] [tinyint] NOT NULL,
 CONSTRAINT [PK_ParcelRange] PRIMARY KEY CLUSTERED 
(
    [ParcelRangeID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [DATA]
) ON [DATA]

GO

ALTER TABLE [dbo].[ParcelRange] ADD  DEFAULT ((-1)) FOR [NdswCustomerID]
GO

ALTER TABLE [dbo].[ParcelRange] ADD  DEFAULT ((-1)) FOR [PickupAddressID]
GO

ALTER TABLE [dbo].[ParcelRange] ADD  DEFAULT ((-1)) FOR [OrganizationID]
GO

ALTER TABLE [dbo].[ParcelRange] ADD  DEFAULT ((-1)) FOR [DepotID]
GO

ALTER TABLE [dbo].[ParcelRange] ADD  DEFAULT ((0)) FOR [IsVTG]
GO

ALTER TABLE [dbo].[ParcelRange] ADD  DEFAULT ((0)) FOR [IsInternal]
GO

ALTER TABLE [dbo].[ParcelRange] ADD  DEFAULT ((0)) FOR [IsInterCompany]
GO

ALTER TABLE [dbo].[ParcelRange] ADD  DEFAULT (getdate()) FOR [Created]
GO

ALTER TABLE [dbo].[ParcelRange] ADD  DEFAULT (getdate()) FOR [Modified]
GO

ALTER TABLE [dbo].[ParcelRange] ADD  DEFAULT ((0)) FOR [UpdateCount]
GO

ALTER TABLE [dbo].[ParcelRange] ADD  DEFAULT (getdate()) FOR [ValidFrom]
GO

ALTER TABLE [dbo].[ParcelRange] ADD  DEFAULT (CONVERT([date],'9999-12-31')) FOR [ValidTo]
GO

ALTER TABLE [dbo].[ParcelRange] ADD  DEFAULT ((1)) FOR [IsActive]
GO

编辑 (4)

我正在使用 Entity Framework 5.0,将尝试更新到更高版本。

编辑 (5) 更新到 EF 6.1,同样的问题 这是我的连接字符串:

metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=XXX.XXX.XXX.XXX\DEV;initial catalog=DPDCDB_ODS;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient

【问题讨论】:

你能发布你的控制器代码吗?还是您调用 db.SaveChanges() 的部分? 将您的整个模型发布到 ParcelRange。 您可以发布您的查看代码吗?感觉模型绑定没做好。 StoreGeneratedPattern :身份。从我尝试过多次的数据库更新。 【参考方案1】:

"(I have included the field in my view as HiddenFor)"

由于它是数据库生成的主键,在create 视图中它没有初始值,您不应该使用HiddenFor 来保存该属性。只需删除那个HiddenFor

如果您使用脚手架向导创建 EF 控制器,您应该注意主键永远不会出现在 create 视图中。

更新:http://robjoosentest.azurewebsites.net/parcelranges

我使用了提供的表脚本,创建了一个数据库,将其导出到 Azure,创建了一个 VS 2013 MVC Web 应用程序,然后创建了基于 EF 模型的控制器和表视图。然后我将它发布到 Azure,它运行良好(微软干得好,让我们看看有人在 5 分钟内使用 Amazon S3 做到这一点!):)。我怀疑这是您的一个库的版本(可能是 EF 版本)。否则,它可能是您的网络应用程序上其他数据库活动的副作用。

【讨论】:

刚才试过了,结果db.SaveChanges()出现了DBUpdateConcurrencyException; (删除了 HiddenFor btw 的完整代码行) 有了一个干净的项目,只有模型(ParcelRangeClass)我创建了一个新的控制器和视图(NExt-Next-Finish),而且还有 DBUpdateConcurrencyException。备注:该类有一些字段代表一些计算字段(DateTime由数据库插入)并且数据库中有一些约束(默认值) 为此我在 ParcelRange 类构造函数中添加了默认部分作为测试。 @Rob Joosen:我拿走了你的桌子,创建了一个数据库(在 Azure 上),创建了一个新的 MVC 项目,一个带有视图的 EF 模型,create 工作得很好。 robjoosentest.azurewebsites.net/parcelranges你用的是什么版本的EF? 太酷了...我现在没有可用的环境,但明天会检查(CET)非常感谢您的努力!【参考方案2】:

当我向我们的 DBA 提出这个问题时,他立即为我指明了正确的方向。

此特定表上有触发器.....这些触发器导致 DBUpdateConcurrencyException。我们禁用了这些触发器,并且插入运行良好

我们现在必须找出如何模仿 C# 中的触发器或使用 STP 通过 EF 更新/插入记录。

感谢您的支持!

【讨论】:

以上是关于主键 mvc 实体框架模型错误的主要内容,如果未能解决你的问题,请参考以下文章

如何在实体框架中使用字符串属性作为主键

INSTEAD OF INSERT 设置的主键在实体框架中抛出错误(ASP.NET 框架 c#)

EF生成实体模型注意事项

VS 2017 中的 MySQL 和 MVC 实体框架不工作

向实体框架模型添加键以满足需要键?

在 Toastr 或使用 MVC4 和实体框架的类似方法中显示错误和异常