简体   繁体   English

添加和保存时未将EF实体提交到数据库是单独的方法

[英]EF entities not being committed to database when adding and saving are separate methods

I am trying to create an expense report application using Razor and EF. 我正在尝试使用Razor和EF创建费用报告应用程序。 I have two entities: 1. ExpenseReport and 2. LineItem. 我有两个实体:1. ExpenseReport和2. LineItem。 There is a 1:N relationship using FK b/t ExpenseReport and LineItem. 使用FK b / t ExpenseReport和LineItem存在1:N关系。 I need to allow the user to fill out the properties of a ExpenseReport and add a number of LineItems. 我需要允许用户填写ExpenseReport的属性并添加许多LineItem。

The user should see a table of line items as they are added to the ExpenseReport. 用户将订单项表添加到ExpenseReport时看到。

The commit to the database should save the ExpenseReport and the LineItems together, maintaining the FK relationship. 提交到数据库应将ExpenseReport和LineItems保存在一起,并保持FK关系。

After three days of seemingly stabbing around in the dark, I cannot seem to wrap my head around what is a very simple scenario. 经过三天似乎在黑暗中刺伤,我似乎无法将脑袋围绕在一个非常简单的场景上。 I've read many articles where requirements are NOT to save the child entity when saving the parent entity, but couldn't glean any insights from those resources. 我读过许多文章,其中的要求是在保存父实体时不保存子实体,但无法从这些资源中收集任何见解。

    public class ExpenseReport
    {
        public Guid ID { get; set; }
        [Required]
        public Guid UserID { get; set; }
        [Required]
        public string Title { get; set; }
        ...
        public virtual List<LineItem> LineItems { get; set; } = new List<LineItem>();
    }

    public class LineItem
    {       
        public int ID { get; set; }
        [Required]
        public Guid ExpenseReportID { get; set; } // FK ExpenseReport
        [Required]
        public int LineItemTypeID { get; set; } // Also a FK
        public string Note { get; set; }
        [Required]
        [DataType(DataType.Currency)]
        public decimal Amount { get; set; }
    }

I have two buttons in the UI attached to different handlers. 我的UI中有两个按钮分别连接到不同的处理程序。 One hard codes a new LineItem, sets the properties on the ExpenseReport and adds the ExpenseReport to the DbContext. 一个硬编码一个新的LineItem,在ExpenseReport上设置属性,然后将ExpenseReport添加到DbContext。 The other just commits the changes. 另一个只是提交更改。

Buttons to call the two different methods: <input type="submit" value="Add Expenses" asp-page-handler="AddExpense" class="btn btn-default" /> <input type="submit" value="Create" asp-page-handler="Create" class="btn btn-default" /> 调用两种不同方法的按钮: <input type="submit" value="Add Expenses" asp-page-handler="AddExpense" class="btn btn-default" /> <input type="submit" value="Create" asp-page-handler="Create" class="btn btn-default" />

    private readonly WebApp1.Data.ApplicationDbContext _context;
    // constructor
    public CreateModel(WebApp1.Data.ApplicationDbContext context)
    {
        _context = context;
    }

    public IActionResult OnPostAddExpense()
    {
        if(!ModelState.IsValid)
        {
            return Page();
        }

        ExpenseReport.ID = Guid.NewGuid();
        ExpenseReport.Status = ExpenseReportStatus.Submitted;
        ExpenseReport.Created = DateTime.Now;
        Guid userId = new Guid(HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier));
        ExpenseReport.UserID = userId;
        _context.ExpenseReport.Add(ExpenseReport);
        LineItem lineItem = new LineItem
        {
            LineItemTypeID = 1,
            ExpenseReportID = ExpenseReport.ID,
            Amount = 125.00M,
            Note = "Note"
        };
        //_context.LineItem.Add(lineItem); // Tried with and without
        ExpenseReport.LineItems.Add(lineItem); // Tried with and without
        _context.ExpenseReport.Update(ExpenseReport); // Tried with and without
        return Page();
    }

    public async Task<IActionResult> OnPostCreateAsync()
    {
        await _context.SaveChangesAsync();
        return RedirectToPage("./Index");
    }

If I place the _context.ExpenseReport.Add(ExpenseReport) method call and _context.SaveChangesAsync() in the same method the ExpenseReport and LineItem is created with the relationship intact. 如果我将_context.ExpenseReport.Add(ExpenseReport)方法调用和_context.SaveChangesAsync()放在同一方法中,则会创建具有完整关系的ExpenseReport和LineItem。 The goal is to allow the user to add/edit/delete the LineItems "in memory" then commit to database at once. 目标是允许用户“在内存中”添加/编辑/删除LineItem,然后立即提交到数据库。

Any help is greatly appreciated. 任何帮助是极大的赞赏。 UPDATED: Providing code asked for in the comment. 更新:提供注释中要求的代码。

Like Mojtaba Tajik has said the DBContext is being lost between the two post request. 就像Mojtaba Tajik所说的那样,两次发布请求之间DBContext丢失了。 Rather than having the user create a in memory object on the server you could have the line item information stored on the client side. 与其让用户在服务器上创建一个内存对象,不如将行项目信息存储在客户端。 You could do this with a cookie or session storage assuming this is a web application. 假设这是一个Web应用程序,则可以使用Cookie或会话存储来完成。 Then once the user has added all the line items they need to the report you could then submit everything at once with one post request. 然后,一旦用户将所需的所有订单项添加到报告中,您就可以一次提交一个帖子请求就提交所有内容。

Here is some information on using session storage - https://www.w3schools.com/jsref/prop_win_sessionstorage.asp 以下是有关使用会话存储的一些信息-https: //www.w3schools.com/jsref/prop_win_sessionstorage.asp

Also I developed a similar sounding application we used a shopping cart approach to our line items. 我还开发了一个类似的探测应用程序,我们对订单项使用了购物车方法。

Edit- The end goal is to accomplish everything within 1 post request. 编辑-最终目标是在1个请求后完成所有任务。 From all my experience dealing with DBContext and object life times it would be easiest to do everything inside of one post request. 从我处理DBContext和对象生命周期的所有经验来看,在一个发布请求中执行所有操作将是最简单的。

-Good luck. -祝好运。

Your problem is that you add some items in one HTTP post method and want to save theme in other HTTP post method for example by clicking "Save" button. 您的问题是,您在一种HTTP发布方法中添加了一些项目,并且想要以其他HTTP发布方法保存主题,例如,通过单击“保存”按钮。 if you do this the .Net Core behavior is normal because of it's architecture. 如果这样做,由于其体系结构,.Net Core行为是正常的。 The state of everything reset with each request because of your DB context life cycles. 由于数据库上下文的生命周期,每个请求的所有状态都会重置。

You should use in memory databases like "Redis" and do add/edit/delete operation in it and at the end by user clicking "Save" button, join the "Redis" stored records in one request and save them to database. 您应该在“ Redis”之类的内存数据库中使用,并在其中进行添加/编辑/删除操作,最后,用户单击“保存”按钮,将“ Redis”存储的记录加入一个请求中,然后将其保存到数据库中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM