поле приращения в структуре объекта в зависимости от значения другого поля - PullRequest
2 голосов
/ 29 ноября 2011

Я новичок в Entity Framework и у меня есть проблема с чем-то, что было довольно просто в чистом t-sql.Предположим, что у нас есть таблица с 3 столбцами.Id (идентификатор, первичный ключ), IdKind (int), Number (int).Столбец Nubmer зависит от столбца IdKind.Данные в этой таблице должны выглядеть следующим образом:

Id |IdKind |Номер

1 |1 |1

2 |1 |2

3 |1 |3

4 |2 |1

5 |2 |2

6 |2 |3

Как видно, номер столбца автоматически увеличивается в зависимости от IdKind.В t-sql я нашел max (Number) + 1 для некоторого IdKind.Все было в одной хранимой процедуре в одной транзакции, так что значение Number было уникальным для IdKind.

Как сделать то же самое в Entity Framework.Значение Number следует вычислять при создании нового объекта или при изменении IdKind.

Ответы [ 2 ]

4 голосов
/ 29 ноября 2011

Я бы использовал для этого триггер базы данных и настроил бы свойство Number в отображении EF с помощью StoreGeneratedPattern.Computed, чтобы сообщить EF, что это свойство заполнено в базе данных и должно быть перезагружено после каждого обновления / вставки.

Я бы также не использовал max () для каждого нового номера. Вместо этого я бы поддерживал отдельные таблицы, имитирующие последовательности. Эта таблица должна содержать запись для каждой последовательности - в вашем случае запись для IdKind с текущим максимальным номером. Вместо выбора агрегации вы выберете одну запись и обновите ее, чтобы она содержала новый максимальный номер. Работа с этой таблицей должна осуществляться в той же транзакции, что и постоянные изменения в вашей сущности.

2 голосов
/ 04 февраля 2016

У меня была такая же проблема, но я решил ее в c #.

У меня должен быть объект, сопоставленный с таблицей:

public class MyEntity
{ 
     Kind IdKind{get; set;}
     int Number{get;set;}
}

У меня должен быть и вспомогательный объект для хранения последнего числа, использованного для каждого вида.

public class LastNumber
{ 
     Kind IdKind{get;set;}
     int LastNumber{get;set;}
}

Тогдаперед добавлением строки (объекта MyEntity) в таблицу я должен рассчитать правильное число, используя поле LastNumber в LastNumberEntity, где Kind равно моему значению Kind.

Мы должны отметить, что в этой стратегии есть проблема параллелизма, посколькудва разных потока могут добавлять объект одного и того же вида одновременно, эти потоки будут проверять один и тот же LastNumberEntity, чтобы получить значение LastNumber.Эта проблема имеет известное решение в сущности.Код может выглядеть следующим образом:

 public int GetNumber(Kind idKind)
    {
        using (var db = new MyDataContext())
        {
            var lastNumber = db.LastNumbers.Single(x=>x.IdKind == idKind);
            for (int attemps = 0; attemps < 10;)
            {
                try
                {
                    lastNumber.LastNumber++;
                    db.SaveChanges();
                    return lastNumber.LastNumber;
                }
                catch (DbUpdateConcurrencyException ex)
                {
                    attemps++;
                }
            }
        }

        throw new Exception("Many concurrency calls");
    }

Этот метод получает инкрементное число для указанного вида и обрабатывает проблему параллелизма, используя его, мы можем установить значение Number для каждого объекта MyEntity.Код клиента может выглядеть следующим образом:

var entity = new MyEntity();
var number = GetNumber(entity.IdKind);
entity.Number = number;
db.MyEntities.Add(entity);
db.SaveChanges();

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...