我将 Breeze 与 Durandal(仍然是 1.2)一起使用,但我遇到了一个我还没有找到简单解决方案的问题。我有 2 个实体:Invoice 和 InvoiceLine,如下所述:
public class Invoice
{
[Key]
public int Id { get; set; }
public string InvoiceNumber { get; set; }
public string Comment { get; set; }
public double? TotalExclVAT { get; set; }
public double? TotalInclVAT { get; set; }
public double? TotalVAT { get; set; }
public bool? WithoutVAT { get; set; }
public virtual List<InvoiceLine> Lines { get; set; }
}
public class InvoiceLine
{
[Key]
public int Id { get; set; }
public string Description { get; set; }
public double VatPercent { get; set; }
public double Amount { get; set; }
public int InvoiceId { get; set; }
public virtual Invoice Invoice { get; set; }
}
我需要在 2 种情况下计算发票总额(TotalExclVAT、TotalInclVAT、TotalVAT):
每当有人添加/修改发票行时。
每当有人更改
WithoutVAT
发票上的标志时。
我认为执行此计算客户端不是一个好主意。主要出于安全原因,执行此服务器端更好。
我的第一个想法是在BeforeSaveEntity
Invoice & InvoiceLine 中完成这项工作。
这是我所做的:
public bool BeforeSaveEntity(EntityState entityState, EntityInfo entityInfo)
{
var invoice = entityInfo.Entity as Invoice;
...
ComputeTotal(entityInfo, invoice);
}
private void ComputeTotal(EntityInfo entityInfo, Invoice invoice)
{
var query = Context.InvoiceLines.Where(x => x.invoiceId == invoice.Id).AsEnumerable();
double totalExclVAT = 0;
double totalVAT = 0;
int percent = 0;
foreach (var line in query.ToList())
{
totalExclVAT = ...
totalVAT = ...
}
entityInfo.OriginalValuesMap.Add("TotalExclVAT", invoice.TotalExclVAT);
entityInfo.OriginalValuesMap.Add("TotalInclVAT", invoice.TotalInclVAT);
entityInfo.OriginalValuesMap.Add("TotalVAT", invoice.TotalVAT);
accounting.TotalExclVAT = totalExclVAT;
accounting.TotalInclVAT = totalExclVAT + totalVAT;
accounting.TotalVAT = totalVAT;
}
对发票行执行相同的操作。正如您在 ComputeTotal 函数中看到的那样,我执行查询以从 DB 获取发票行,然后计算总计并将结果保存在发票中。
它不能很好地工作:如果在我的发票上添加新行,在我的数据库上执行查询不会得到这个添加的行!因为它还没有存储在数据库中。
继续进行客户端会更容易,但我认为这不是一个好主意......是吗?
所以我确信还有另一种方法,但我自己没有找到。
非常感谢任何帮助。
更新
下面是我第一次解决这个问题。
public Dictionary<Type, List<EntityInfo>> BeforeSaveEntities(Dictionary<Type, List<EntityInfo>> saveMap)
{
List<EntityInfo> invoices;
List<EntityInfo> invoiceLines;
EntityInfo ei;
if (!saveMap.TryGetValue(typeof(InvoiceLine), out invoiceLines))
{
// if we fall here it means no invoice lines exists in the saveMap
}
if (!saveMap.TryGetValue(typeof(Invoice), out invoices))
{
// if we fall here it means no invoices exists in the saveMap
// >> getting the invoice from DB and add it to the map
using (var dc = new BreezeContext())
{
int invoiceId = ((InvoiceLine)invoiceLines[0].Entity).InvoiceId;
EFContextProvider<BreezeContext> cp = new EFContextProvider<BreezeContext>();
var acc = dc.Invoices.Where(x => x.Id == invoiceId).FirstOrDefault();
ei = cp.CreateEntityInfo(acc, Breeze.WebApi.EntityState.Modified);
invoices = new List<EntityInfo>();
saveMap.Add(typeof(Invoice), invoices);
invoices.Add(ei);
}
}
// There is only 1 invoice at a time in the saveMap
Invoice invoice = (Invoice)invoices[0].Entity;
ei = invoices[0];
Dictionary<int, InvoiceLine> hashset = new Dictionary<int, InvoiceLine>();
// Retrieving values of invoice lines from database (server side)
using (var dc = new BreezeContext())
{
var linesServerSide = dc.InvoiceLines.Where(x => x.InvoiceId == invoice.Id).AsEnumerable();
foreach (var elm in linesServerSide)
{
hashset.Add(elm.Id, elm);
}
}
// Retrieving values of invoice lines from modified lines (client side)
foreach (var entityInfo in invoiceLines)
{
InvoiceLine entity = (InvoiceLine)entityInfo.Entity;
switch (entityInfo.EntityState)
{
case Breeze.WebApi.EntityState.Added:
hashset.Add(entity.Id, entity);
break;
case Breeze.WebApi.EntityState.Deleted:
hashset.Remove(entity.Id);
break;
case Breeze.WebApi.EntityState.Modified:
hashset.Remove(entity.Id);
hashset.Add(entity.Id, entity);
break;
}
}
// Computing totals based on my hashset
double totalExclVAT = 0;
double totalInclVAT = 0;
double totalVAT = 0;
foreach (var elm in hashset)
{
InvoiceLine line = elm.Value;
totalExclVAT += line.Amount;
totalVAT += line.Amount * (int)line.VatPercent.Value / 100;
}
totalInclVAT = totalExclVAT + totalVAT;
// Adding keys if necessary
if (!ei.OriginalValuesMap.ContainsKey("TotalExclVAT"))
ei.OriginalValuesMap.Add("TotalExclVAT", invoice.TotalExclVAT);
if (!ei.OriginalValuesMap.ContainsKey("TotalInclVAT"))
ei.OriginalValuesMap.Add("TotalInclVAT", invoice.TotalInclVAT);
if (!ei.OriginalValuesMap.ContainsKey("TotalVAT"))
ei.OriginalValuesMap.Add("TotalVAT", invoice.TotalVAT);
// Modifying total values
invoice.TotalExclVAT = totalExclVAT;
invoice.TotalInclVAT = totalInclVAT;
invoice.TotalVAT = totalVAT;
return saveMap;
}
每当在客户端修改发票和 invoiceLines 时,上述解决方案都可以正常工作。当客户端没有修改发票(仅修改行)时,我遇到了问题。在这种情况下,我需要通过从数据库中获取相关发票将其添加到 saveMap。如您所见,这就是我在代码中所做的。但是我需要为我在这里手动修改的属性添加键,OriginalValuesMap
在这种情况下我不能,因为我的字典对象为空。然后当我做...
ei.OriginalValuesMap.Add("TotalExclVAT", invoice.TotalExclVAT);
...在一个空对象(OriginalValuesMap)上它不起作用。
所以我的新问题现在是下一个:如何将实体添加到数据库中已经存在的 saveMap。所以我不想将此实体标记为ei = cp.CreateEntityInfo(acc, Breeze.WebApi.EntityState.Add);
,而是ei = cp.CreateEntityInfo(acc, Breeze.WebApi.EntityState.Modified);
. 在这种情况下,我的 OriginalValuesMap 为空,这似乎是一个问题。
希望你能理解我在这里试图解释的内容。