Сравнивайте телефонные номера без учета какого-либо формата в Linq с объектами, а также проверяйте производительность

1

Мне нужно сравнить номера телефонов в Linq с объектами. Я использую Regex, чтобы я мог сравнивать только числа при игнорировании формата.

Поскольку мы не можем использовать предложение Regex в where, чтобы получить список телефонных номеров, а затем применить цикл для сравнения номеров телефонов.

Вот код:

    /// <summary>
    /// Check Phone number exist or Not
    /// </summary>
    /// <param name="accountNumber"></param>
    /// <returns></returns>
    public bool CheckPhoneNumberExist(string phoneNumber)
    {
        LP= new LPEntities();

        // In order to compare phone number, we need to use regex so that we can compare only numbers and not any specific format
        phoneNumber = Regex.Replace(phoneNumber, "[^0-9]", "");

        var phoneList = (from act in LP.Accounts
                         select act).ToList();
        if (phoneList.Count > 0)
        {
            foreach (var item in phoneList)
            {
                if (item.Telephone != null)
                {
                    if (Regex.Replace(item.Telephone, "[^0-9]", "") == phoneNumber)
                    {
                        return true;
                    }
                }
            }
        }

        return false;
      }

Код работает нормально, но есть проблема с производительностью. У нас есть 20 тысяч записей в базе данных, которые продолжают расти, поэтому медленнее создавать список, а затем перебирать этот список.

Как мы можем оптимизировать вышеуказанное? Есть ли какое-то другое решение, например, если мы можем сделать это с помощью хранимой процедуры?

Благодаря,

Теги:
sql-server
entity-framework

3 ответа

3
Лучший ответ

Обратите внимание, что ваша техника регулярных выражений не будет определять, что эти числа на самом деле одинаковы:

+441234567890
+44 (0)1234 567890
01234 567890

Мой первый выбор состоял в том, чтобы сохранить номер как varchar без форматирования и только форматировать его для отображения. Это означает, что вы избавитесь от регулярного выражения при поиске, и вы можете добавить индекс, чтобы ускорить его еще больше.

Моим вторым выбором было бы добавить столбец, чтобы вы сохранили оба и синхронизировали их.

См. Ответы здесь:

Лучше ли хранить номера телефонов в каком-то каноническом формате или "как указано"?

Наконец, вы можете получить некоторое улучшение, если вы измените свой linq на это:

bool exists = (from act in LP.Accounts
               where act.Telephone != null //move the null check to the database
               select act.Telephone)  //select only the telephone number
              .AsEnumerable()  //using linq-to-objects
                               //after retrieving the results from the database
                               //lets you use Regex 
                               //- but it does get them all into memory
              .Any(pn => Regex.Replace(pn, "[^0-9]", "") == phoneNumber) 
              //Any stops at the first one 
              //better than Counting them all then checking '> 0'

Как в сторону. Добавление проверки, if (phoneList.Count > 0) избыточно перед foreach (var item in phoneList) потому что тело цикла не выполняется, если в списке нет элементов.

  • 0
    Да, хранение простого числа в базе данных хорошо, но его существующие функциональные возможности для хранения формата, поэтому я не могу изменить. Выражение Linq работает хорошо, большое спасибо! Подскажите, пожалуйста, как работает «AsEnumerable и Any».
  • 0
    Попробуйте посмотреть на stackoverflow, например stackoverflow.com/q/5311034/150342 и stackoverflow.com/q/305092/150342
1

Я пробовал один новый подход, когда я заменяю символы дополнительного формата на "", как указано ниже

select account, telephone from account where 
Replace(Replace(Replace(Replace(Replace(telephone, '-',''), '(',''),')',''),' ',''),'+',''
    )='9084336325'

но он будет работать только тогда, когда мы будем понятны для замены других символов.

0

Во-первых, вы загружаете весь список сущностей, которые вы выполняете с двумя регулярными выражениями для каждой проверки. Что-то вроде этого должно быть более эффективным:

public bool CheckPhoneNumberExist(string newPhoneNumber)
{
    LP = new LPEntities();

    var phoneList = (from act in LP.Accounts
                     select act).ToList();

    foreach (string phoneNumber in phoneList)
        Add(phoneNumber);

    return Add(newPhoneNumber);
}

private HashSet<string> _uniquePhoneNumbers = new HashSet<string>();

public bool Add(string phoneNumber)
{
    // Only use Regex if necessary
    if (!IsNumeric(phoneNumber))
        phoneNumber = RemoveNonNumericCharacters(phoneNumber);

    // Returns false if string already exists in HashSet
    return !_uniquePhoneNumbers.Add(phoneNumber);
}

private static readonly char[] _forbiddenChars = new char[] { ',', '.', '.', ' ', '+', '-' };

private static bool IsNumeric(string s)
{
    foreach(char c in _forbiddenChars)
        if(s.IndexOf(c) >= 0)
            return false;

    return true;
}

private static string RemoveNonNumericCharacters(string s)
{
    return Regex.Replace(s, "[^0-9]", "");
}

Другой подход заключается в том, чтобы убедиться, что номера сохраняются в стандартизованном формате с самого начала.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню