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

C# 添加和保存时未提交到数据库的EF实体是单独的方法,c#,entity-framework,razor,C#,Entity Framework,Razor,我正在尝试使用Razor和EF创建一个费用报告应用程序。我有两个实体:1。费用报告和2。行项目。使用FK b/t ExpenseReport和LineItem存在1:N关系。 我需要允许用户填写ExpenseReport的属性并添加许多行项目 用户应在将行项目添加到ExpenseReport时看到行项目表 提交到数据库应将ExpenseReport和行项目保存在一起,以维护FK关系 在黑暗中摸索了三天之后,我似乎无法理解一个非常简单的场景。我读过许多文章,其中要求在保存父实体时不保存子实体,但无

我正在尝试使用Razor和EF创建一个费用报告应用程序。我有两个实体:1。费用报告和2。行项目。使用FK b/t ExpenseReport和LineItem存在1:N关系。 我需要允许用户填写ExpenseReport的属性并添加许多行项目

用户应在将行项目添加到ExpenseReport时看到行项目表

提交到数据库应将ExpenseReport和行项目保存在一起,以维护FK关系

在黑暗中摸索了三天之后,我似乎无法理解一个非常简单的场景。我读过许多文章,其中要求在保存父实体时不保存子实体,但无法从这些资源中获得任何见解

    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; }
    }
公共类支出报告
{
公共Guid ID{get;set;}
[必需]
公共Guid用户标识{get;set;}
[必需]
公共字符串标题{get;set;}
...
公共虚拟列表行项目{get;set;}=new List();
}
公共类行项目
{       
公共int ID{get;set;}
[必需]
公共Guid ExpenseReportID{get;set;}//FK ExpenseReport
[必需]
public int LineItemTypeID{get;set;}//也是一个FK
公共字符串注释{get;set;}
[必需]
[数据类型(数据类型.货币)]
公共十进制数{get;set;}
}
我在UI中有两个按钮连接到不同的处理程序。硬编码一个新的行项目,设置ExpenseReport的属性,并将ExpenseReport添加到DbContext。另一个只是提交更改

用于调用两种不同方法的按钮:

private只读WebApp1.Data.ApplicationDbContext\u上下文;
//建造师
公共CreateModel(WebApp1.Data.ApplicationDbContext上下文)
{
_上下文=上下文;
}
公共IActionResult on PostaddExpense()
{
如果(!ModelState.IsValid)
{
返回页();
}
ExpenseReport.ID=Guid.NewGuid();
ExpenseReport.Status=ExpenseReportStatus.Submitted;
ExpenseReport.Created=DateTime.Now;
Guid userId=新Guid(HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier));
ExpenseReport.UserID=用户ID;
_context.ExpenseReport.Add(ExpenseReport);
LineItem LineItem=新的LineItem
{
LineItemTypeID=1,
ExpenseReportID=ExpenseReport.ID,
金额=125.00米,
Note=“Note”
};
//_context.LineItem.Add(LineItem);//尝试使用和不使用
ExpenseReport.LineItems.Add(lineItem);//尝试使用和不使用
_context.ExpenseReport.Update(ExpenseReport);//尝试使用和不使用
返回页();
}
公共异步任务OnPostCreateAync()
{
wait_context.SaveChangesAsync();
返回页首(“/索引”);
}
如果将
\u context.ExpenseReport.Add(ExpenseReport)
方法调用和
\u context.savechangesync()
放在同一个方法中,则创建ExpenseReport和LineItem时关系保持不变。目标是允许用户添加/编辑/删除“内存中”的行项目,然后立即提交到数据库

非常感谢您的帮助。
更新:提供评论中要求的代码

您的问题是,您在一个HTTP post方法中添加了一些项目,并希望在其他HTTP post方法中保存主题,例如单击“保存”按钮。如果您这样做,.Net核心行为是正常的,因为它的体系结构。由于数据库上下文的生命周期,每一个请求都会重置所有内容的状态


您应该使用诸如“Redis”之类的内存数据库,并在其中执行添加/编辑/删除操作,最后用户单击“保存”按钮,将“Redis”存储的记录加入一个请求并保存到数据库中。

就像Mojtaba Tajik所说的那样,DBContext在两个post请求之间丢失。您可以将行项目信息存储在客户端,而不是让用户在服务器上创建内存中的对象。假设这是一个web应用程序,您可以使用cookie或会话存储来实现这一点。然后,一旦用户将他们需要的所有行项目添加到报告中,您就可以通过一个post请求立即提交所有内容

下面是有关使用会话存储的一些信息-

我还开发了一个类似的应用程序,我们使用购物车的方法来处理我们的商品

编辑-最终目标是在一个post请求内完成所有事情。根据我处理DBContext和对象生命周期的所有经验,在一个post请求内完成所有工作都是最简单的


-祝你好运。

你能告诉我们如何调用这两个方法(添加/保存)的代码吗?还有包含这些方法的类的实例化?Hello@AzharKhorasany,我已经用这些信息更新了帖子。谢谢当您在IoC中注册ApplicationContext时,它的生存期是多少?我不知道如何检查它。您能提供一些指导吗?您在解决方案中使用DI吗?如何注册/初始化ApplicationContext?
    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");
    }