首先使用代码执行从一对多的关联 entity framework
Perform an Association from one to many with code first entity framework
我首先将 EF 6.1 与代码一起使用,然后尝试定义一个 class 发票,它可以包含多个时间表实例。
我希望它做的是在数据库中插入一个新的发票行(它确实这样做了),然后 更新 时间表 table 以便外国InvoiceId 的键从 NULL 更改为新创建的发票的 ID。
不幸的是,正在发生的是 新行 被插入到时间表 table 中,并且这些行与新生成的发票相关联。
我的 class 是:
public class TimeSheet
{
public int Id { get; set; }
public DateTime WeekStart { get; set; }
public List<TimeSheetLine> TimeSheetLines { get; set; }
public int? InvoiceId { get; set; }
public virtual Invoice Invoice { get; set; }
}
public class Invoice
{
public int Id { get; set; }
public int? AgencyId { get; set; }
public int? ClientId { get; set; }
public int Rate { get; set; }
public Client Client { get; set; }
public Agency Agency { get; set; }
public List<TimeSheet> Timesheets { get; set; }
}
还有一个映射class:
public class TimeSheetMap : EntityTypeConfiguration<TimeSheet>
{
public TimeSheetMap()
{
this.HasKey(x => x.Id);
this.ToTable("TimeSheet");
this.HasOptional(x => x.Invoice)
.WithMany(x => x.Timesheets)
.HasForeignKey(x => x.InvoiceId);
}
}
编辑
构建发票对象的代码:
public bool GenerateInvoice(InvoiceVM invoice)
{
//create an Invoice record from the InvoiceVM
Invoice inv = new Invoice();
List<TimeSheet> sheets = new List<TimeSheet>();
foreach (var item in invoice.TimesheetList)
{
TimeSheet ts = manager.GetTimesheetById(item.Id);
sheets.Add(ts);
}
inv.Timesheets = sheets;
//save the invoice
manager.GenerateInvoice(inv);
return true;
}
编辑 2 经理 class
public bool GenerateInvoice(Invoice invoice)
{
bool ret = false;
using (DataContext dc = new DataContext())
{
dc.Invoices.Add(invoice);
dc.SaveChanges();
ret = true;
}
return ret;
}
我可以做任何明显的改变来让它工作吗?
您似乎在使用一个上下文从数据库中提取发票,并使用一个单独的上下文来保存发票。 GenerateInvoice
函数中的 DataContext
不知道 TimeSheets
已经在数据库中,因为它们是由不同的上下文检索的,在 manager.GetTimesheetById(item.Id);
.
有几种方法可以处理这个过程,这里有两个选项:
在 manager.GenerateInvoice()
中执行查找和附加,而不是在 ViewModel 中。这将是最干净的方法,但需要经理处理时间表。即:
Public bool GenerateInvoice(Invoice invoice, List<TimeSheet> timesheets)
{
bool ret = false;
using (DataContext dc = new DataContext())
{
foreach (var item in timesheets)
{
TimeSheet ts = dc.GetTimesheetById(item.Id);
invoice.TimeSheets.Add(ts);
}
dc.Invoices.Add(invoice);
dc.SaveChanges();
ret = true;
}
return ret;
}
执行两次单独的数据库调用,一次插入 Invoice
,返回发票 Id
,第二次更新时间表。
public int GenerateInvoice(Invoice invoice)
{
using (DataContext dc = new DataContext())
{
dc.Invoices.Add(invoice);
dc.SaveChanges();
}
return invoice.Id;
}
public bool GenerateInvoice(InvoiceVM invoice)
{
//create an Invoice record from the InvoiceVM
Invoice inv = new Invoice();
//handle other fields for invoice here
//create invoice, with no timesheets
int invoiceId = manager.GenerateInvoice(inv);
//loop through the timesheets and assign the invoice to them.
using (DataContext dc = new DataContext())
{
foreach (var item in invoice.TimesheetList)
{
TimeSheet ts = dc.GetTimesheetById(item.Id);
ts.InvoiceId = invoiceId;
}
dc.SaveChanges();
}
return true;
}
您可能需要重构这些解决方案中的任何一个以适应您的完整域模型,但希望这些方法可以将您推向正确的方向。
这里的根本问题是我在每个存储库方法中都这样做了
using (DataContext dc = new DataContext())
这意味着对象跟踪完全丢失了。根据我的经验,我不建议这样做。
我改为使用模块级别的 DbContext,它可用于将操作分组到工作单元中。一旦我这样做了,所有生成的 SQL 就开始像我认为的那样工作,相关实体在数据库中被正确更新。
我首先将 EF 6.1 与代码一起使用,然后尝试定义一个 class 发票,它可以包含多个时间表实例。
我希望它做的是在数据库中插入一个新的发票行(它确实这样做了),然后 更新 时间表 table 以便外国InvoiceId 的键从 NULL 更改为新创建的发票的 ID。 不幸的是,正在发生的是 新行 被插入到时间表 table 中,并且这些行与新生成的发票相关联。
我的 class 是:
public class TimeSheet
{
public int Id { get; set; }
public DateTime WeekStart { get; set; }
public List<TimeSheetLine> TimeSheetLines { get; set; }
public int? InvoiceId { get; set; }
public virtual Invoice Invoice { get; set; }
}
public class Invoice
{
public int Id { get; set; }
public int? AgencyId { get; set; }
public int? ClientId { get; set; }
public int Rate { get; set; }
public Client Client { get; set; }
public Agency Agency { get; set; }
public List<TimeSheet> Timesheets { get; set; }
}
还有一个映射class:
public class TimeSheetMap : EntityTypeConfiguration<TimeSheet>
{
public TimeSheetMap()
{
this.HasKey(x => x.Id);
this.ToTable("TimeSheet");
this.HasOptional(x => x.Invoice)
.WithMany(x => x.Timesheets)
.HasForeignKey(x => x.InvoiceId);
}
}
编辑 构建发票对象的代码:
public bool GenerateInvoice(InvoiceVM invoice)
{
//create an Invoice record from the InvoiceVM
Invoice inv = new Invoice();
List<TimeSheet> sheets = new List<TimeSheet>();
foreach (var item in invoice.TimesheetList)
{
TimeSheet ts = manager.GetTimesheetById(item.Id);
sheets.Add(ts);
}
inv.Timesheets = sheets;
//save the invoice
manager.GenerateInvoice(inv);
return true;
}
编辑 2 经理 class
public bool GenerateInvoice(Invoice invoice)
{
bool ret = false;
using (DataContext dc = new DataContext())
{
dc.Invoices.Add(invoice);
dc.SaveChanges();
ret = true;
}
return ret;
}
我可以做任何明显的改变来让它工作吗?
您似乎在使用一个上下文从数据库中提取发票,并使用一个单独的上下文来保存发票。 GenerateInvoice
函数中的 DataContext
不知道 TimeSheets
已经在数据库中,因为它们是由不同的上下文检索的,在 manager.GetTimesheetById(item.Id);
.
有几种方法可以处理这个过程,这里有两个选项:
在
manager.GenerateInvoice()
中执行查找和附加,而不是在 ViewModel 中。这将是最干净的方法,但需要经理处理时间表。即:Public bool GenerateInvoice(Invoice invoice, List<TimeSheet> timesheets) { bool ret = false; using (DataContext dc = new DataContext()) { foreach (var item in timesheets) { TimeSheet ts = dc.GetTimesheetById(item.Id); invoice.TimeSheets.Add(ts); } dc.Invoices.Add(invoice); dc.SaveChanges(); ret = true; } return ret; }
执行两次单独的数据库调用,一次插入
Invoice
,返回发票Id
,第二次更新时间表。public int GenerateInvoice(Invoice invoice) { using (DataContext dc = new DataContext()) { dc.Invoices.Add(invoice); dc.SaveChanges(); } return invoice.Id; } public bool GenerateInvoice(InvoiceVM invoice) { //create an Invoice record from the InvoiceVM Invoice inv = new Invoice(); //handle other fields for invoice here //create invoice, with no timesheets int invoiceId = manager.GenerateInvoice(inv); //loop through the timesheets and assign the invoice to them. using (DataContext dc = new DataContext()) { foreach (var item in invoice.TimesheetList) { TimeSheet ts = dc.GetTimesheetById(item.Id); ts.InvoiceId = invoiceId; } dc.SaveChanges(); } return true; }
您可能需要重构这些解决方案中的任何一个以适应您的完整域模型,但希望这些方法可以将您推向正确的方向。
这里的根本问题是我在每个存储库方法中都这样做了
using (DataContext dc = new DataContext())
这意味着对象跟踪完全丢失了。根据我的经验,我不建议这样做。
我改为使用模块级别的 DbContext,它可用于将操作分组到工作单元中。一旦我这样做了,所有生成的 SQL 就开始像我认为的那样工作,相关实体在数据库中被正确更新。