0

我将 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):

  1. 每当有人添加/修改发票行时。

  2. 每当有人更改WithoutVAT发票上的标志时。

我认为执行此计算客户端不是一个好主意。主要出于安全原因,执行此服务器端更好。

我的第一个想法是在BeforeSaveEntityInvoice & 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 为空,这似乎是一个问题。

希望你能理解我在这里试图解释的内容。

4

1 回答 1

0

有什么理由不为此使用触发的存储过程吗?这肯定是最简单的方法......

但是......如果有,那么另一种方法是使用“BeforeSaveEntities”而不是“BeforeSaveEntity”,因为这将使您可以访问整个“SaveMap”。

然后为每个修改过的发票创建所有 invoiceLines 的哈希集,并将其构造为每个发票的发票行的服务器端查询与与此发票关联的客户端 invoiceLines 的组合(来自 SaveMap)。接下来只需汇总每个 hashSet 并使用此更新您的“Totalxxx”属性。

有点简洁,但希望这是有道理的。

于 2013-09-05T17:34:07.647 回答