Я привык к использованию столбцов идентификации и создания pk для меня. Мне интересно, есть ли способ охватить столбец идентификатора или иначе вычислить его как уникальный в пределах внешнего ключа?Как выполнить вычисляемые значения столбцов в SQL Server с Entity Framework
Например, используя столбец идентификации таблицы может выглядеть следующим образом:
| UserId | WidgetId | <-- Table Widget, WidgetId is identity column & pk
---------------------
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 4 |
| 2 | 5 |
| 2 | 6 |
Что делать, если я хочу, чтобы достичь чего-то больше похоже на следующее:
| UserId | WidgetId | <-- Table Widget, both UserId and WidgetId compose the pk
---------------------
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 2 | 2 |
| 2 | 3 |
Я знаю, что EF позволяет database- генерируемые значения столбцов, такие как идентификация и вычисление. Мой вопрос в том, как можно достичь вычисленного столбца, подобного этому?
Я понимаю, что это можно сделать в приложении, найдя самый высокий WidgetId, который пользователь имеет и увеличивает на единицу. Но это не похоже, что это правильный путь.
Я предполагаю, что это также возможно сделать с помощью триггера, но добавление триггера в db из DbContext
будет устанавливать зависимость от РСУБД, не так ли?
Есть ли лучший способ, который требует меньше зависимости от того, какой бэкэнд использует EF?
Обновление
Для того, чтобы быть более ясным, в приведенной выше модели, существует определения отношения между Widget пользователя и по назначению. UserId является первичным ключом таблицы User и, если FK принадлежит пользователю как часть PK Widget, это означает, что Widgets никогда не разделяются между пользователями. Когда пользователь удаляется, все Виджеты удаляются вместе с ним. Запрос Widget от WidgetId не имеет смысла; Для запроса конкретного виджета необходимы параметры UserId и WidgetId.
Я изучаю это, потому что я помню, как читал в Evans DDD, что идентификатор объекта без полномочий root в агрегате должен быть уникальным в совокупности. Выше приведен пример этого случая:
кроме корня ENTITIES имеет локальную идентичность, но идентичность должна быть различимы только в агрегированном, потому что вне объекта никогда не сможет увидеть его из контекста от корня ENTITY. (Domain-Driven Design, Evans)
Update 2
После ответа Горган, я осуществили что-то вроде следующего в моей виджет фабрики класса. Это правильный подход для достижения желаемого результата?
public class WidgetFactory : BaseFactory
{
private object _sync = new object();
internal WidgetFactory(IWriteEntities entityWriter) : base(entityWriter)
{
// my DbContext class implements the IWriteEntities interface
}
public Widget CreateOrUpdate(User user, int? widgetId, string prop1,
bool prop2, string prop3)
{
Widget widget = null;
if (!widgetId.HasValue)
{
// when widgetId is null do a create (construct & hydrate), then
EntityWriter.Insert(widget); // does DbEntityEntry.State = Added
}
else
{
// otherwise query the widget from EntityWriter to update it, then
EntityWriter.Update(widget); // does DbEntityEntry.State = Modified
}
// determine the appropriate WidgetId & save
lock (_sync)
{
widget.WidgetId = widgetId.HasValue ? widget.WidgetId
: EntityWriter.Widgets.Where(w => w.UserId == user.Id)
.Max(w => w.WidgetId) + 1;
EntityWriter.SaveChanges(); // does DbContext.SaveChanges()
}
return widget;
}
}
Widget
Я предполагаю, что я не должен был замаскирован этот термин. Фактическим объектом является WorkPlace. Я создаю приложение, чтобы отслеживать, где я работаю в течение года, так как я должен каждый год представлять маршрут с моей формой возврата муниципального налога. Когда закончите, я планирую опубликовать его в облаке, чтобы другие могли использовать его бесплатно. Но, конечно, я хочу, чтобы их WorkPlaces были полностью изолированы от моих.
Пользователи создаются автоматически для каждого посетителя, используя анонимную идентификацию/Request.AnonymousID
(позже будет функция регистрации, но нет необходимости пробовать демонстрацию). Веб-приложение будет иметь похожие URL-адреса/рабочие места/1,/work-places/2 и т. Д. Поскольку каждый запрос гарантированно имеет пользователя, идентификатор пользователя не должен быть идентифицирован в URL-адресе. Я могу идентифицировать пользователей от Request.AnonymousID
, когда ничего не найдено в User.Identity.Name
.
Если WorkPlaceId был столбцом идентификации, сначала мне необходимо проверить действия контроллера, чтобы убедиться, что пользователь владеет рабочим местом перед его отображением. В противном случае я мог бы взломать URL-адрес, чтобы увидеть каждый WorkPlace, который каждый пользователь установил в системе. Сделав WorkPlaceId уникальным только для пользователя, мне не нужно об этом беспокоиться. URL/work-places/1 будет отображать совершенно разные данные для двух разных пользователей.
Если вы используете EF 5, вы должны пометить его этим. – Yuck
Удивительный, последний раз, когда я проверил, он еще не был создан. Спасибо за головы. – danludwig
Да, это об этом, но я хотел бы узнать больше о том, что представляет этот виджет, поскольку это кажется неестественным и, как будто должен быть лучший способ его моделировать. –