在性能方面检查重复实体的好方法是什么

What is a good way in terms of performance to check duplicate entity

我需要在将实体保存到数据库之前检查重复条目。下面是我当前的代码

if (db.Product.Any(x => x.Code == entity.Code))
{
  error.Add('Duplicate code');
}

if (db.Product.Any(x => x.Name == entity.Name))
{
  error.Add('Duplicate name');
}

if (db.Product.Any(x => x.OtherField == entity.OtherField))
{
  error.Add('Duplicate other field');
}

上面代码的问题是它进行了 3 db 调用来验证实体。此 table 有数百万条记录,此应用程序将被数千名用户使用。所以它会严重损害性能。不过我可以让它成为一个查询

if (db.Product.Any(x => x.Code == entity.Code || x.Name == entity.Name || x.OtherField == entity.OtherField))
{
  error.Add('Duplication found');
}

第二个代码的问题是我不知道哪个字段是重复的。

这样做的更好方法是什么?我应该只依赖于数据库中的唯一约束吗?但是来自数据库的错误很难看。

编辑

如果超过 1 个重复字段,我需要向用户显示所有错误。 考虑场景:如果重复字段是代码和名称。如果我告诉用户代码已经存在,那么他会更改代码并再次尝试保存。然后显示第二个错误(名称字段)。它使用户在成功保存之前点击保存几次。

1- 您可以 select 复制实体

var product = db.Product.FirstOrDefault(x => x.Code == entity.Code
                                               || x.Name == entity.Name
                                               || x.OtherField == entity.OtherField);

if (product == null)
;//no duplicates

if (product.Code == entity.Code)
{
  error.Add('Duplicate code');
}

if (product.Name == entity.Name)
{
  error.Add('Duplicate name');
}

if (product.OtherField == entity.OtherField)
{
  error.Add('Duplicate other field');
}

2- 您可以创建用于插入的存储过程并检查其中的重复项;

编辑: 好的,你可以这样写

    var duplicates = (from o in db.Products
              select new
              {
                  codeCount = db.Products.Where(c => c.Code == entity.Code).Count(),
                  nameCount = db.Products.Where(c => c.Name == entity.Name).Count(),
                  otherFieldCount = db.Products.Where(c => c.OtherField == entity.OtherField).Count()
              }).FirstOrDefault();

这将 select 每个重复字段的数量。 需要注意的一件事:无论如何,您应该在数据库中具有唯一约束,因为在您验证和保存数据时,可能会在您插入之前插入具有这些值的另一行。

你可以这样做:

    string duplicateField;

    bool validationResult = db.Product.Any(x => {
            if(x.Code == entity.Code){
            duplicateField = "Code";
                return true;
            }
    // Other field checks here

}

if(validationResult){
// Error in field <duplicateField>
}

如果你在NameCodeOtherField字段上有索引,那么重复检查不会太长,但仍然是3次调用数据库而不是1.

在这种情况下通常的解决方案是计算重复项。那么如果count等于0,就没有重复。

Here 你会找到一些技巧来做到这一点。

简短示例:

var counts =(
    from product in db.Products
    group product by 1 into p
    select new
    {
        Name = p.Count(x => x.Name == name),
        Code = p.Count(x => x.Code == code),
        OtherField = p.Count(x => x.OtherField == otherFields)
    }
).FirstOrDefault();

if (counts.Name > 0)
    error.Add("Duplicate name");

if (counts.Code > 0)
    error.Add("Duplicate code");

更新:看来可以用更简单的方法解决问题:

var duplicates =(
    from product in db.Products
    group product by 1 into p
    select new
    {
        Name = p.Any(x => x.Name == name),
        Code = p.Any(x => x.Code == code),
        OtherField = p.Any(x => x.OtherField == otherFields)
    }
).FirstOrDefault();

if (duplicates.Name)
    error.Add("Duplicate name");