我使用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
时。
我认为执行此计算客户端不是一个好主意。出于安全原因,执行此服务器端更好。
我的第一个想法是在Invoice&amp;的BeforeSaveEntity
中完成这项工作。 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获取发票行,然后计算总计并将结果保存在发票中。
效果不佳:如果在我的发票上添加新行,则在我的数据库上执行查询时不会获得此添加的行!因为它尚未存储在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是客户端修改的。当客户端没有修改发票时(我修改了行),我遇到了问题。在这种情况下,我需要通过从DB获取相关发票到saveMap。这就是我在代码中所做的,你可以看到。但是我需要为我在这里手动修改的属性添加OriginalValuesMap
的密钥,在这种情况下我不能因为我的字典对象为空。然后当我做...
ei.OriginalValuesMap.Add("TotalExclVAT", invoice.TotalExclVAT);
...在null对象(OriginalValuesMap)上它不起作用。
所以我的新问题现在是下一个:如何将实体添加到DB上已存在的saveMap。所以我不想将此实体标记为ei = cp.CreateEntityInfo(acc, Breeze.WebApi.EntityState.Add);
,而是ei = cp.CreateEntityInfo(acc, Breeze.WebApi.EntityState.Modified);
。在这种情况下,我的OriginalValuesMap为空,似乎是一个问题。
希望你能理解我在这里解释的内容。
答案 0 :(得分:0)
有没有理由不为此使用触发存储过程?这肯定是最简单的方法......
但是......如果有,那么另一种方法是使用'BeforeSaveEntities'而不是'BeforeSaveEntity',因为这样可以访问整个'SaveMap'。
然后为每个修改后的发票创建所有invoiceLines的哈希集,并将其构建为每个发票的发票行的服务器端查询与与此发票关联的客户端invoiceLines(来自SaveMap)重叠的组合。接下来只是总计每个hashSet并使用此更新您的'Totalxxx'属性。
有点简洁,但希望这是有道理的。