【问题标题】:Cannot set the [Key] property of the model when saving new records保存新记录时无法设置模型的[Key]属性
【发布时间】:2011-12-17 09:22:37
【问题描述】:

所以,我已经迁移到 MVC3,总的来说,我认为这很棒;我也很喜欢 codefirst 方法。

我今天遇到了一些麻烦,在 MVC2 下我能够添加记录并编辑它们,但现在无法这样做。

我知道这是一个模糊的开始,所以请允许我详细说明。

这是我的一个模型的示例

namespace ESF_ResourceManager.Models
{
    public class FileList
    {
        [Key]
        public int FileListID { get; set; }

        [DisplayName("File title: ")]
        [Required(ErrorMessage = "Please set a unique title for the file")]
        // TODO: Need to add remote validation - must be unique
        public string FileTitle { get; set; }

        [DisplayName("Choose a File")]
        [FileExtensions(Extensions = "txt, zip, pdf, ppt, xls, doc, docx, xlsx, pptx", ErrorMessage = "Please choose a valid file of type txt, zip, pdf, ppt, xls, doc, docx, xlsx or pptx")]
        public HttpPostedFileBase FileUrl { get; set; }

    }
}

然后对应的控制器:

namespace ESF_ResourceManager.Controllers
{
    public class FileListController : ResourceManagerController
    {
        //
        // GET: /FileList/

        public ActionResult Index()
        {
            var fileList = from fl in DBContext.FileLists
                           where fl.FileListID > 0
                           select fl;

            return View(fileList.ToList());
        }


        //
        // GET: /FileList/Create
        [HttpGet]
        public ActionResult Create()
        {
            return View();
        }

        //
        // POST: /FileList/Create

        [HttpPost]
        public ActionResult Create(FileList fileDetail)
        {
            if (ModelState.IsValid)
            {
                // test the file - size only - the file type should have been checked via Extensions as par tof the model definition
                if (fileDetail.FileUrl.ContentLength > 0 && fileDetail.FileUrl.ContentLength < 1048576)
                {
                    string fileName = Path.GetFileName(fileDetail.FileUrl.FileName);
                    string path = Path.Combine(Server.MapPath("~/App_Data/uploads/documents"), fileName);
                    fileDetail.FileUrl.SaveAs(path);

                    DBContext.FileLists.Add(fileDetail);
                    DBContext.SaveChanges();
                    return RedirectToAction("Index");

                }
            }

            return View(fileDetail);
        }

        //
        // GET: /FileList/Edit/5
        [HttpGet]
        public ActionResult Edit(int id)
        {
            var fileDetail = from fl in DBContext.FileLists
                             where fl.FileListID == id
                             select fl;
            return View(fileDetail.Single());
        }

        //
        // POST: /FileList/Edit/5

        [HttpPost]
        public ActionResult Edit(int id, FileList fileDetail)
        {

            if (ModelState.IsValid)
            {
                var fileEdited = DBContext.FileLists.Find(id);
                UpdateModel(fileEdited);
                DBContext.SaveChanges();
                return RedirectToAction("Index");
            }

            return View();

        }

        //
        // GET: /FileList/Delete/5

        public ActionResult Delete(int id)
        {
            var fileDetail = from fl in DBContext.FileLists
                             where fl.FileListID == id
                             select fl;
            return View(fileDetail.Single());
        }

        //
        // POST: /FileList/Delete/5

        [HttpPost]
        public ActionResult Delete(int id, FileList fileDetail)
        {
            try
            {
                DBContext.FileLists.Remove(DBContext.FileLists.Find(id));
                DBContext.SaveChanges();
                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }
    }
}

Razor 的视图是(用于创建):

@model ESF_ResourceManager.Models.FileList

@{
    ViewBag.Title = "File List";
    Layout = "~/Views/Shared/_Layout.cshtml";
}


    @using (Html.BeginForm("Create", "FileList", FormMethod.Post, new { enctype = "multipart/form-data" }))
    {
        @Html.ValidationSummary(true)
        <fieldset>
            <legend>File List</legend>

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

            <div class="editor-label">
                @Html.LabelFor(model => model.FileUrl) 
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(model => model.FileUrl, new { type = "file" })
                @Html.ValidationMessageFor(model => model.FileUrl) 
            </div>

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

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

因此,我可以加载视图并查看表单以输入数据,但是当我单击“创建”按钮时,我收到以下消息:

值不能为空。参数名称:key

我查看了调试器中的对象,进入 create post 函数的对象上没有任何内容为空。关键是 0,我会(可能错误地)期望它是 1。

所以我的第一个问题是我在这里错过了什么?我需要做什么才能让它正常工作?

第二个问题更笼统——我的数据在哪里?我读过的教程表明,要么是 SQLExpress 数据库创建了某个地方,要么是在 App_Data 中创建了 SqlCE。这两个我都找不到,所以我很困惑这是哪里。

对此的任何帮助将不胜感激。

非常感谢 nathj07

编辑

感谢您的光临,我仍在学习在提问时包含哪些内容会有所帮助。所以,这里是要求的项目:

数据上下文

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;

namespace ESF_ResourceManager.Models
{
    public class ResourceManagerContext : DbContext
    {
        public DbSet<Resource> Resources { get; set; }
        public DbSet<ResourceType> ResourceTypes { get; set; }
        public DbSet<User> Users { get; set; }
        public DbSet<FileList> FileLists { get; set; }
    }
}

Web.Config

<?xml version="1.0"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=152368
  -->

<configuration>
  <appSettings>
    <add key="webpages:Version" value="1.0.0.0"/>
    <add key="ClientValidationEnabled" value="true"/>
    <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
  </appSettings>

  <system.web>
    <compilation debug="true" targetFramework="4.0">
      <assemblies>
        <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      </assemblies>
    </compilation>

    <authentication mode="Forms">
      <forms loginUrl="~/Account/LogOn" timeout="2880" />
    </authentication>

    <pages>
      <namespaces>
        <add namespace="System.Web.Helpers" />
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
        <add namespace="System.Web.WebPages"/>
      </namespaces>
    </pages>
  </system.web>

  <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

最后——

视图/Web.config

<?xml version="1.0"?>

<configuration>
  <configSections>
    <sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
      <section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
      <section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
    </sectionGroup>
  </configSections>

  <system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="System.Web.Mvc.WebViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>

  <appSettings>
    <add key="webpages:Enabled" value="false" />
  </appSettings>

  <system.web>
    <httpHandlers>
      <add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/>
    </httpHandlers>

    <!--
        Enabling request validation in view pages would cause validation to occur
        after the input has already been processed by the controller. By default
        MVC performs request validation before a controller processes the input.
        To change this behavior apply the ValidateInputAttribute to a
        controller or action.
    -->
    <pages
        validateRequest="false"
        pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
        pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
        userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
      <controls>
        <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
      </controls>
    </pages>
  </system.web>

  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />

    <handlers>
      <remove name="BlockViewHandler"/>
      <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
    </handlers>
  </system.webServer>
</configuration>

如果你还有什么需要看的,我会很乐意把它贴出来。

谢谢 nathj07

编辑 2 我现在尝试手动添加 SQLExpress 数据库并更新 web.config 文件中的连接字符串。

 <connectionStrings>
    <remove name="LocalSqlServer"/>
    <add name="LocalSqlServer" connectionString="Data Source=.\SQLExpress;Integrated Security=True;AttachDBFilename=|DataDirectory|DB_ESF_ResourceManager.mdf;User Instance=true" />
  </connectionStrings>

这给我留下了同样的错误——完全没有区别。我对此完全不知所措,不知道下一步该去哪里。对此还有什么建议吗?

谢谢 nathj07

【问题讨论】:

  • 我们可能还需要两件事 1) 如果您明确指定了连接字符串,您的 databasecontext 类和 web.config
  • 现在的问题是什么?您上面提到的例外(我刚刚突出显示了该消息)?还是找不到或者无法创建数据库?
  • 好的,问题并没有什么不同。基本上我尝试重新创作这项工作。该项目有 4 个模型——资源类型、资源、用户和文件列表。重新创建了文件列表的所有栏后,我注意到一切正常。如图所示,我添加了文件列表模型,但出现错误。这次我没有连接字符串,我假设(我知道不好)这已经在 SQLServerExpress 或 CE 的某个地方创建了一个数据库。我现在还有其他几个问题,但我会在新线程中发布这些问题。感谢所有的帮助。我会相应地投票 nathj07
  • 如何“假设”数据库已经创建?您不能简单地检查数据库是否存在吗?如果您根本不指定任何连接字符串,它将是一个 SQL Server Express DB(请参阅下面的答案)。数据库确实是您必须找到的第一件事,以确定您的异常原因。
  • 嗨,Slauma,我完全同意。我们不知道如何找到数据库。 Sql 管理快递没有找到任何要连接的东西。关于如何找到这个的任何想法?

标签: asp.net asp.net-mvc-3 entity-framework-4 ef-code-first sql-server-express


【解决方案1】:

EF 似乎没有将您的密钥标记为标识列。如果类型为intshortlong,并且名称为&lt;classname&gt;Id,Entity Framework 将属性标记为主键。在您的模型上,“ID”部分是大写的。您有两种可能的解决方案:

  • [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 放在您的属性上方,表明它实际上是一个身份列
  • 将您的资源从 FileListID 重命名为 FileListId。如果您选择此解决方案,您可能也不再需要 [Key] 属性。

如果您选择第一个解决方案,您的财产将如下所示:

[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int FileListID { get; set; }

【讨论】:

  • 主要或外部检测不区分大小写,因此IDId 都可以。
  • Slauma,感谢您澄清这一点。我认为它不区分大小写,因为我有一个使用大写 ID 的演示解决方案。
  • Jesse,感谢关于设置 [DatabaseGenerated] 注释的提示,它教会了我一些很棒的新东西。
【解决方案2】:

你还需要为 mvc make bind 添加 FileListID

@Html.HiddenFor(model => model.FileListID)

【讨论】:

  • 嗨,费尔南多,我之前尝试添加一个可见字段,但没有任何区别。当我回来工作时,我会尝试一个隐藏的领域。谢谢 nathj07
  • 您好,费尔南多 - - 代码在保管箱中,所以我在家里尝试过,但没有奏效。你还有更多答案吗?我确实在原始问题中添加了更多代码。再次感谢您的帮助。
【解决方案3】:

你的第二个问题:

因为您的 web.config 文件中没有任何连接字符串,如果数据库不存在,Entity Framework 4.1 将尝试在您的 SQL Server Express 实例中创建一个新数据库。此数据库的名称是 Namespace.DerivedContextName,因此在您的情况下应该是:ESF_ResourceManager.Models.ResourceManagerContext

您可以使用 SQL Server Management Studio 或在 Visual Studio 中通过服务器资源管理器查看数据库。

你的第一个问题:

您收到错误的一个可能原因是数据库中与您的模型中的键属性FileListID 对应的键列未标记为标识列,即当您使用时自动生成自己的值的列插入一个新行。您的模型配置假定该列是一个标识(默认情况下,您没有将其关闭)。因此,当您插入新对象时,EF 不会将 FileListID 的值发送到数据库,因为它假定数据库将创建一个值。如果数据库中的列不是标识,则它不会创建值,并且您会遇到异常。

因此,如果FileListID 是标识列,则应检查数据库,如果不是,则将其打开。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多