首页 > 解决方案 > ASP.NET MVC 在单个 HTTP 发布请求中更新主从记录

问题描述

我正在自学 C# 和 MVC,但有 SQL 背景。在单个操作中更新现有的主从记录集(例如客户订单和订单详细信息)时,更新主记录没有问题。关于详细记录,我看到的示例只是删除所有现有详细信息,然后将它们重新添加,而不是仅添加、删除或更新已更改的内容。这看起来简单有效,但涉及对数据库记录的不必要更改,并且可能是复杂关系中的一个问题。

我尝试编写代码来检查现有值与发布的值,以确定每个细节的正确实体状态(添加、删除、修改、未更改)。使用 LINQ except 和 Intersect 来完成这个工作,但似乎会导致意外的性能下降。

(相反,我可以将原始值加载到原始 GET 请求中的“oldValue”隐藏字段中,以与 POST 值进行比较,除非这在多用户环境中不可靠并且似乎是个坏主意。)

我很乐意提供代码示例,但我的问题更多是关于最佳实践。是否有更新现有主从记录集的首选方法?

编辑:我在回答问题时添加了下面的代码。在此示例中,我们的应用程序允许将附加属性附加到产品,并保存在单独的表 ProductAttributes 中。该视图允许用户在同一网页上编辑产品和属性并同时保存。该代码运行良好,但在 SaveChanges 上似乎很慢并且滞后。

public ActionResult Edit(Product product) 
{
    if (ModelState.IsValid)
    {
        db.Entry(product).State = EntityState.Modified;

        // Establish entity states for product attributes.

        List<ProductAttribute> existingAttributes = new List<ProductAttribute>();
        existingAttributes = db.ProductAttributes.AsNoTracking()
            .Where(x => x.Sku == product.Sku).ToList();

        // Review each attribute that DID NOT previously exist.
        foreach (ProductAttribute pa in product.ProductAttributes
            .Except(existingAttributes, new ProductAttributeComparer()))
        {
            if (pa.Value is null)
            {
                // Value didn't exist and still doesn't.
                db.Entry(pa).State = EntityState.Unchanged;
            }
            else
            {
                // New value exists that didn't before.
                db.Entry(pa).State = EntityState.Added;
            }
        }

        // Review each attribute that DID previously exist.
        foreach (ProductAttribute pa in product.ProductAttributes
            .Intersect(existingAttributes, new ProductAttributeComparer()))
        {
            if (pa.Value is null)
            {
                // Value existed and has been cleared.
                db.Entry(pa).State = EntityState.Deleted;
            }
            else
            {
                if (pa.Value != existingAttributes
                    .FirstOrDefault(x => x.Attribute == pa.Attribute).Value)
                {
                    // Value has been altered.
                    db.Entry(pa).State = EntityState.Modified;
                }
                else
                {
                    // Value has not been altered.
                    db.Entry(pa).State = EntityState.Unchanged;
                }
            }
        }

        db.SaveChanges();
        return RedirectToAction("Details", new { id = product.ProductId });
    }
    return View(product);
}

internal class ProductAttributeComparer : IEqualityComparer<ProductAttribute>
{
    public bool Equals(ProductAttribute x, ProductAttribute y)
    {
        if (string.Equals(x.Attribute, y.Attribute, 
            StringComparison.OrdinalIgnoreCase))
        {
            return true;
        }
        return false;
    }

    public int GetHashCode(ProductAttribute obj)
    {
        return obj.Attribute.GetHashCode();
    }
}

}

标签: c#asp.net-mvc

解决方案


推荐阅读