Как реализовать порядковый номер записей в бд?

Сабж. К примеру есть такая модель

public class SettingRedirect
{
  public int Id { get; set; }
  public int Identifier { get; set; }
  public string Name { get; set; }
}

В бд несколько записей, в Identifier хранится их порядковый номер. Порядковый номер записей будет иногда меняться. К примеру мы извлекаем объект с номером 10, и перемещаем его вверх по списку выставляя номер 5. Но запись с номером 5 уже существует, получается надо сделать так 10=>5=>6=>7=>8=>9=>10.
Можно делать запрос к бд и выбирать сразу все записи, и если произошло изменение то делаем +1 в Identifier ко всем записям которые ниже по порядку.
В общем вопрос в том есть ли какой то встроенный механизм для реализации порядкового номера или может быть есть простое решение?
Пока я только придумал метод который просто будет тупо делать +1.


Ответы (2 шт):

Автор решения: A B

Надеюсь, я правильно поняла задачу.

Условимся, что индекс объекта будет иметь название Index (при желании можно изменить).

Тогда можно создать следующий интерфейс:

public interface IIndex
{
    public int Index { get; set; }
}

Интерфейс IIndex будет требовать наличие поля Index в классах, в которых это будет необходимо (В примере для класса ExampleClass).

Реализуем интерфейс в классе ExampleClass:

public class ExampleClass : IIndex
{
    public int Id { get; set; }
    public int Index { get; set; }
    public string Name { get; set; }
}

Тип данных List предоставляет методы для удобной манипуляции списками (Add, Insert, Remove и прочие). Эти методы могут изменять порядок индексов (как в массивах).

По сути, класс List уже сделал всю "грязную" работу с индексами за нас. Нам лишь нужен метод, который запишет фактическое значение индекса по списку в свойство Index у класса, который реализует интерфейс IIndex. Средствами C# узнать, реализует ли объект интерфейс или нет можно с помощью ключевого слова where.

К классу List было бы хорошо добавить свой метод, манипулирующий свойством Index. Создадим же свой тип данных ListIndex:

public class ListIndex<T> : List<T> where T : IIndex
{
    public void SortIndex() //Обновляет свойство Index, начиная с 1
    {
        for (int i=0;i<this.Count; i++)
        {
            this[i].Index = i+1;
        }
    }
}

В этом классе мы унаследовали весь функционал от List, но указали, что объекты, которые могут там находиться, должны реализовывать IIndex.

Метод SortIndex позволяет обновить все индексы к фактическому значению, но начиная с 1-цы (при желании можно изменить).

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

Файловая структура:

введите сюда описание изображения

Пример работы в Program.cs :

class Program
{
    static void Main(string[] args)
    {
        //Условимся, что по правилам системы некий список индексируется с единицы.
        //Если выборка происходит из БД, то заполняем List по порядку через цикл For

        //Заполнение списка
        ListIndex<ExampleClass> ListObject = new ListIndex<ExampleClass>()
        {
            new ExampleClass {Id=1, Index = 1, Name = "Первый"},
            new ExampleClass {Id=2, Index = 2, Name = "Второй"},
            new ExampleClass {Id=35, Index = 3, Name = "Зелёный"},
            new ExampleClass {Id=7, Index = 4, Name = "Ананас"},
            new ExampleClass {Id=3, Index = 5, Name = "Утюг"}
        };

        Console.WriteLine("Вывод до манипуляции ->");
        for (int i = 0; i < ListObject.Count; i++)
        {
            ExampleClass obj = ListObject[i];
            Console.WriteLine($"{obj.Id}, {obj.Index}, {obj.Name}");
        }

        ExampleClass cloneObject = ListObject.Find(x => x.Id == 35);//Берём объект из списка
        ExampleClass newObject = new ExampleClass() //Клонируем объект
        {
            Id = cloneObject.Id,
            Name = cloneObject.Name,

        };

        newObject.Name = "Вставка"; //Изменяем имя объекта
        ListObject.Insert(2, newObject);//Вставляем на третью позицию в список объект

        ListObject.Add(new ExampleClass() { Id = 87, Name = "Василий" }); //Добавляем новый объект

        Console.WriteLine("\nВывод после манипуляции ->");
        for (int i = 0; i < ListObject.Count; i++)
        {
            ExampleClass obj = ListObject[i];
            Console.WriteLine($"{obj.Id}, {obj.Index}, {obj.Name}");
        }

        ListObject.SortIndex();//Перезаписываем индексы

        Console.WriteLine("\nВывод после \"сортировки\" ->");
        for (int i = 0; i < ListObject.Count; i++)
        {
            ExampleClass obj = ListObject[i];
            Console.WriteLine($"{obj.Id}, {obj.Index}, {obj.Name}");
        }

    }
}

Вывод:

введите сюда описание изображения

P.S.:

  • Если задача единичная, то это можно было бы реализовать в связанной с обновлением индексов функции.
  • В случае необходимости поменять местами объекты в списке, можно добавить соответствующую функцию в класс ListIndex.
  • Если индексы нужно выводить куда-то динамически, то к ним можно обратиться по факту.
  • Если индексы нужно привязывать к WPF-интерфейсу, можно добавить ещё одну функцию (или переопределить Insert), которая изменяет индексы, начиная с вставленной в список записи и до конца (прибавляя 1-цу).
  • Если всю эту работу нужно проделывать в T-SQL, то у него есть функция ROW_NUMBER() (https://docs.microsoft.com/ru-ru/sql/t-sql/functions/row-number-transact-sql?view=sql-server-ver15).
→ Ссылка
Автор решения: WinnerIT

За чем так сложно?

Вариант без autoincrement:

  1. Считываем все записи из таблицы в List или другую collection.
  2. Производим манипуляции над данными: Сортируем, заново присваемваем ID
  3. Если все удачно - опустошаем таблицу
  4. Записаем наш заново отсортированный список в таблицу с помощью INSERT
→ Ссылка