Вопрос
Можно ли определить уникальное ограничение для свойства, используя свободный синтаксис или атрибут? Если нет, каковы обходные пути?
У меня есть класс пользователя с первичным ключом, но я хотел бы убедиться, что адрес электронной почты также уникален. Возможно ли это без непосредственного редактирования базы данных?
Решение (на основе ответа Мэтта)
public class MyContext : DbContext {
public DbSet<User> Users { get; set; }
public override int SaveChanges() {
foreach (var item in ChangeTracker.Entries<IModel>())
item.Entity.Modified = DateTime.Now;
return base.SaveChanges();
}
public class Initializer : IDatabaseInitializer<MyContext> {
public void InitializeDatabase(MyContext context) {
if (context.Database.Exists() && !context.Database.CompatibleWithModel(false))
context.Database.Delete();
if (!context.Database.Exists()) {
context.Database.Create();
context.Database.ExecuteSqlCommand("alter table Users add constraint UniqueUserEmail unique (Email)");
}
}
}
}
ObjectContext
либоDbContext
.Ответы:
Насколько я могу судить, на данный момент нет возможности сделать это с помощью Entity Framework. Однако это проблема не только с уникальными ограничениями ... вы можете также создавать индексы, проверять ограничения и, возможно, триггеры и другие конструкции. Вот простой шаблон, который вы можете использовать с настройкой сначала кода, хотя, по общему признанию, он не зависит от базы данных:
Другой вариант: если ваша модель предметной области является единственным методом вставки / обновления данных в вашу базу данных, вы можете самостоятельно реализовать требование уникальности и не использовать базу данных. Это более переносимое решение, которое заставляет вас четко понимать свои бизнес-правила в коде, но оставляет вашу базу данных открытой для недопустимых данных.
источник
SaveChanges()
), но все же существует вероятность проскальзывания еще одной вставки / обновления между временем проверки уникальности и временемSaveChanges()
. Итак, в зависимости от того, насколько критично приложение и вероятность нарушения уникальности, вероятно, лучше всего добавить ограничение в базу данных.serializable isolation level
(или настраиваемая блокировка таблицы, тьфу) на самом деле позволит вам гарантировать уникальность вашего кода. Но большинство людей не используют егоserializable isolation level
из соображений производительности. По умолчанию в MS Sql Server установленоread committed
. Смотрите серию из 4 частей, начиная с: michaeljswart.com/2010/03/…Начиная с EF 6.1 теперь возможно:
Это даст вам уникальный индекс вместо уникального ограничения, строго говоря. Для большинства практических целей они одинаковы .
источник
На самом деле это не связано с этим, но в некоторых случаях может помочь.
Если вы хотите создать уникальный составной индекс, скажем, для двух столбцов, которые будут действовать как ограничение для вашей таблицы, то начиная с версии 4.3 вы можете использовать новый механизм миграции для этого:
Обычно вам нужно вставить такой вызов в один из сценариев миграции:
Что-то такое:
источник
DropIndex("TableName", new[] { "Column1", "Column2" });
Я делаю полный взлом, чтобы SQL выполнялся при создании базы данных. Я создаю свой собственный DatabaseInitializer и наследую от одного из предоставленных инициализаторов.
Это единственное место, где я мог бы вклиниться в свои операторы SQL.
Это из CTP4. Не знаю, как это работает в CTP5.
источник
Просто пытаясь выяснить, есть ли способ сделать это, единственный способ, который я нашел до сих пор, заключался в том, чтобы обеспечить его сам, я создал атрибут, который будет добавлен к каждому классу, где вы указываете имя полей, которые должны быть уникальными:
Затем в своем классе я добавлю это:
Наконец, я добавлю метод в свой репозиторий, в метод Add или при сохранении изменений следующим образом:
Не слишком хорошо, так как нам нужно полагаться на размышления, но пока этот подход работает для меня! = D
источник
Также в 6.1 вы можете использовать версию ответа @ mihkelmuur с свободным синтаксисом следующим образом:
Беглый метод не идеален, ИМО, но, по крайней мере, теперь он возможен.
Больше подробностей в блоге Артура Виккерса http://blog.oneunicorn.com/2014/02/15/ef-6-1-creating-indexes-with-indexattribute/
источник
Простой способ в Visual Basic с использованием EF5 Code First Migrations
Образец публичного класса
Конец класса
Атрибут MaxLength очень важен для уникального индекса строкового типа.
Запустите cmd: update-database -verbose
после запуска cmd: add-migration 1
в сгенерированном файле
источник
Подобно ответу Тобиаса Шитковски, но С # и имеет возможность иметь несколько полей в константах.
Чтобы использовать это, просто поместите [Уникальный] в любое поле, которое вы хотите сделать уникальным. Для строк вам нужно будет сделать что-то вроде (обратите внимание на атрибут MaxLength):
потому что поле строки по умолчанию - nvarchar (max), и это не будет разрешено в ключе.
Для нескольких полей в ограничении вы можете:
Во-первых, UniqueAttribute:
Затем включите полезное расширение, чтобы получить имя таблицы базы данных из типа:
Затем инициализатор базы данных:
источник
Решил проблему размышлением (извините, ребята, VB.Net ...)
Сначала определите атрибут UniqueAttribute:
Затем улучшите свою модель, например
Наконец, создайте собственный DatabaseInitializer (в моей версии я воссоздаю БД при изменениях БД только в режиме отладки ...). В этом DatabaseInitializer индексы автоматически создаются на основе уникальных атрибутов:
Возможно, это поможет ...
источник
Если вы переопределите метод ValidateEntity в своем классе DbContext, вы также можете поместить туда логику. Преимущество здесь в том, что у вас будет полный доступ ко всем своим DbSet. Вот пример:
источник
Если вы используете EF5 и у вас все еще есть этот вопрос, приведенное ниже решение решило его для меня.
Я использую сначала код, поэтому помещаю:
в сценарии миграции хорошо справились со своей задачей. Он также допускает значения NULL!
источник
Используя подход EF Code First, можно реализовать поддержку уникальных ограничений на основе атрибутов, используя следующую технику.
Создайте атрибут маркера
Отметьте свойства, которые вы хотите сделать уникальными для объектов, например
Создайте инициализатор базы данных или используйте существующий для создания уникальных ограничений.
Настройте контекст базы данных для использования этого инициализатора в коде запуска (например, в
main()
илиApplication_Start()
)Решение похоже на решение Mheyman, но с упрощением, поскольку оно не поддерживает составные ключи. Для использования с EF 5.0+.
источник
Решение Fluent Api:
источник
Сегодня я столкнулся с этой проблемой и, наконец, смог ее решить. Я не знаю, правильный ли это подход, но, по крайней мере, я могу продолжать:
источник
Используйте уникальный валидатор свойств.
ValidateEntity
не вызывается в одной транзакции базы данных. Следовательно, могут существовать состояния гонки с другими объектами в базе данных. Вам нужно немного взломать EF, чтобы заставить транзакциюSaveChanges
(и, следовательно,ValidateEntity
).DBContext
не может открыть соединение напрямую, ноObjectContext
может.источник
Согласно http://blogs.msdn.com/b/adonet/archive/2014/02/11/ef-6-1-0-beta-1-available.aspx , EF 6.1 будет иметь атрибут IndexAttribute, который поможет нам. ,
источник
После прочтения этого вопроса у меня возник собственный вопрос в процессе попытки реализовать атрибут для обозначения свойств как уникальных ключей, таких как ответы Михкеля Мюура , Тобиаса Шиттковски и Мхеймана : Сопоставьте свойства кода Entity Framework с столбцами базы данных (CSpace в SSpace)
Я наконец-то пришел к этому ответу, который может отображать как скалярные, так и навигационные свойства до столбцов базы данных и создавать уникальный индекс в определенной последовательности, указанной в атрибуте. Этот код предполагает, что вы реализовали UniqueAttribute со свойством Sequence и применили его к свойствам класса сущности EF, которые должны представлять уникальный ключ сущности (отличный от первичного ключа).
Примечание. Этот код основан на версии EF 6.1 (или более поздней), которая
EntityContainerMapping
недоступна в предыдущих версиях.источник
Для тех, кто использует конфигурации с первым кодом, вы также можете использовать объект IndexAttribute как ColumnAnnotation и установить для его свойства IsUnique значение true.
Например:
Это создаст уникальный индекс с именем IX_name в столбце Name.
источник
Извините за поздний ответ, но мне было приятно поговорить с вами
Я написал об этом в проекте кода
В общем, это зависит от атрибутов, которые вы добавляете в классы для создания ваших уникальных индексов.
источник