【问题标题】:How do I get Scope_Identity from new record in Entity Framework?如何从实体框架中的新记录中获取 Scope_Identity?
【发布时间】:2021-02-08 09:40:30
【问题描述】:

我尝试了以下示例,这些示例在插入新记录以用于需要将其用作外键的其他表中后获取主键的 id 看起来相当简单,但尽管遵循这些示例我是仍然得到 id 的空引用异常。

我遵循的示例位于https://www.entityframeworktutorial.net/faq/how-to-get-id-of-saved-entity-in-entity-framework.aspx,但我试图在 ASP.NET Core 3.1 中 Razor 页面背后的代码中的异步任务中使用它,如下所示:

private readonly ApplicationDbContext _context;

public IndexModel(ApplicationDbContext context)
{
    _context = context;
}

[BindProperty]
public Posts Posts { get; set; }

public async Task<IActionResult> OnPostAsync()
{
    _context.Posts.Add(Posts);
    await _context.SaveChangesAsync();

    int postid = Posts.Postid;
    string targeturl = linkgenerator.postlink(postid, Posts.Title);

    return RedirectToPage(targeturl);   
}

这会导致生成一个错误的新帖子:

NullReferenceException:对象引用未设置为对象的实例

为什么我无法像示例中所说的那样轻松获得Postid

Posts模型的相关部分如下:

[Key]
public int Postid { get; set; }

新记录的所有输入值都来自 Razor 页面上的表单。单击提交按钮后,我需要获取Postid

更新:反馈表明我应该分享 Razor 页面代码。该代码基本上是这样的:

<form id="newpost" method="post">
        This page has countless controls the reproduction of which would not be efficient for the purpose of this question. Here is one example control
        <div class="form-group row">
            <label class="col-sm-2 col-form-label" asp-for="Posts.Title"></label>
            <div class="col-sm-7">
                <input class="form-control" asp-for="Posts.Title" />
            </div>
            <span class="text-danger col-sm-3 col-form-label" asp-validation-for="Posts.Title"></span>
        </div>
       
        <button type="submit" value="Create" class="btn btn-primary">Submit Post</button>
    </form>

还有一点要补充。这是我的第一个 .Net Core 网站,我之前的所有工作都是使用 ASP.Net WebForms。因此,我有时会遇到很多困难,将页面背后的代码绑定到主页上的控件,因为它们不像 WebForms 控件那样工作。在 WebForms 上,如果我想在插入事件期间获取表单控件的值,我可以通过编写类似 string title = TextBox1.Text.ToString() 的内容来获取该值,并且有一些类似于使用 HttpContext 和 id 的东西表单控件的数量,但这仍然需要表单控件具有值。尚未在表单控件中创建的记录的主键永远不会有值。

在 WebForm 上,我将使用 SqlDataSource 控件并在创建新记录后获取主键的作用域标识值。根据我看到的每个教程,包括我已经链接到 EF 的教程会自动生成范围标识,所以我需要做的就是将我的更改保存到数据库并按照我一直尝试访问它的方式访问它。

【问题讨论】:

  • int 不会获得 NRE。使用您的调试器。您的 Posts 对象为空。您没有在 POST 操作中分配它,
  • 您能分享一下您的剃须刀页面代码吗? @Dai 说, Posts.Postid 似乎为空。
  • 你能解释一下为什么 Posts.Postid 是空的吗?我看到的教程说 Posts.Postid 应该在更改保存到数据库后由 EF 自动生成,所以我需要做的就是访问它是类型 Posts.Postid
  • Posts.Postid 是 Posts 表的自动生成主键。这就是为什么我必须等到 _context.SaveChanges() 或 _context.SaveChangesAsync() 之后才能获得它,因为在 Posts 表中的新条目创建之前它不存在。我能够使用类似 int postid = (int)e.Command.Parameters["@postid"].Value; 之类的东西在原始 WebForms 站点上执行此操作。在 SqlDataSource_Inserted 事件期间,但我无法在我的新 Razor Pages 网站上复制它。
  • 我自己创建了一个测试演示,效果很好。我可以得到 ID,结果图像:url。建议你可以尝试修改save changes代码为var re = await _context.SaveChangesAsync();查看save changes结果是否为1,确保save操作正确,

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


【解决方案1】:

事实证明,您需要创建一个新对象并手动分配每个值。如果您这样做,则范围标识在保存后变得可用,但由于某种原因,您不能仅仅依靠将 Razor Pages 上的基本表单绑定到模型的默认方法来获得它。

这是一个有效的例子

var newPost = new Posts();
            newPost.Title = Posts.Title;
await _context.Posts.AddAsync(newPost);
            await _context.SaveChangesAsync();
            int postid = newPost.Postid;

即使您在 Posts.Title 的 razor 页面中的表单上有绑定输入,这也是必需的,因为如果不创建新的 Posts 对象,您将无法获取 Posts 对象的范围标识。我问微软为什么,但他们的工作人员都不会解释为什么会这样。

【讨论】:

    猜你喜欢
    • 2011-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多