#c# #entity-framework
#c# #entity-framework
Вопрос:
В настоящее время я пытаюсь создать пользовательское ограничение с помощью C # Entity Framework. Более подробно:
У меня есть числовое поле, которое может иметь только определенные значения (например, 1, 2 и 3). Как мне достичь этого ограничения в среде code first?
Комментарии:
1. Что со всеми тегами Entity Framework?
2. Извините, удалил дубликаты
Ответ №1:
Entity Framework автоматически проверяет любые проверки, которые вы добавляете в свою модель с помощью ValidationAttribute
s. RequiredAttribute
или RangeAttribute
— это два примера встроенных подклассов этого атрибута.
Если вам нужна какая-то пользовательская проверка, самый удобный способ — воспользоваться этим механизмом и создать свой собственный ValidationAttribute
подкласс.
Если вы хотите проверить несмежный диапазон значений, который вы не можете использовать RangeAttribute
, но вы могли бы создать собственный атрибут, например, такой:
public class AllowedValuesAttribute : ValidationAttribute
{
private readonly ICollection<object> _validValues;
private readonly Type _type;
public AllowedValuesAttribute(Type type, object[] validValues)
{
_type = type;
_validValues = validValues.Where(v => v != null amp;amp; v.GetType() == type).ToList();
}
public override bool IsValid(object value)
{
return value.GetType() == _type amp;amp; _validValues.Contains(value);
}
public override string FormatErrorMessage(string name)
{
return string.Format("Value for '{0}' is not an allowed value", name);
}
}
Использование:
[AllowedValues(typeof(int), new object[] { 1, 2, 4, 8, 16 })]
public int Base { get; set; }
Обратите внимание, что здесь мы должны использовать фиксированные значения, потому что содержимое атрибута должно быть известно во время компиляции. Кроме того, мы должны использовать object
, потому что (в настоящее время) C # не поддерживает универсальные атрибуты. Помимо этого, существует множество вариантов. Например, у атрибута также может быть метод, который находит разрешенные значения во время выполнения, возможно, из именованного источника, поэтому вы можете указать это имя в его конструкторе.
Я не вижу никакой проблемы в украшении классов сущностей атрибутами проверки. Модель сущности не является моделью предметной области, это часть уровня доступа к данным. Его основной целью является (и должно быть) облегчение доступа приложения к данным. Если модель сущности также поддерживает бизнес-логику, это просто бонус.
Комментарии:
1. подумав об этом, я все еще понятия не имею, зачем s.o. использовать это. Атрибут для этого просто неверный. Это видно из вашего примера: здесь это было бы
Flag
—Enum
или простоеEnum
, если бы значения были, например,1,3,7,20,...
. Если данные имеют определенное значение, вы бы создали таблицу и использовали PK как FK. Если вам действительно нужно использовать int (потому что, не знаю почему), вы бы обработали это в контроллере или использовали аннотацию в viewmodel, поскольку другой контроллер, возможно, мог бы ввести другой int — (если нет, перечислите или FK это).. Извините, но я все еще не вижу никаких причин для его использования в классе сущностей.2. @MatthiasBurger В приложении вы хотите иметь единую точку проверки . Я бы никогда не стал использовать средство установки свойств, которое выдает исключение. Это вводит множество потенциальных мест кода, где должны обрабатываться исключения. И когда запускается проверка EF, свойство не проверяется. Преимущество атрибута в том, что он проверяется в нужное время и правильным образом, т. Е. так же, как и другие проверки EF. Любые нарушения красиво перечислены среди других ошибок проверки. Вы получаете многое бесплатно.
3. @MatthiasBurger Конечно, я бы не стал использовать его для проверки FK и да, я бы рекомендовал перечисления. В относительно простых случаях может быть достаточно атрибута.
4. проблема с проверкой верна, и я согласен с этим пунктом. Но imo entity-class слишком поздно для такого рода проверки. Поскольку это проверка представления, я думаю, она уже должна быть проверена в viewmodel (если только вы не используете viewmodels и не используете классы сущностей в своих представлениях). Viewmodel также может быть базовым классом для viewmodels, так что у вас есть эта единственная точка проверки. Например. an
AccountViewModel
является базовым дляLoginViewModel
иRegisterViewModel
. Я бы проверил почтовый адрес вAccountViewModel
и отправил действительные данные в entity-classApplicationuser
. Или я ошибаюсь?5. @MatthiasBurger, с которым я полностью согласен 🙂 Мне не нравится перебрасывать полные объекты entity по проводам. Но модели представления также могут иметь атрибуты. Все зависит от предпочтений. Например, с ASP.Net MVC, работа с атрибутами проверки (в любом классе модели) очень удобна. Тем не менее, атрибуты проверки (или реализации
IValidatableObject
— мое предпочтение) в классах сущностей обеспечивают хорошую окончательную защиту от попадания мусора в базу данных.
Ответ №2:
Добавлять примечания к данным в domain-model — очень плохая практика, как писал Д.Мак. Так что насчет того, чтобы сделать это более приятным способом?
public MyClass
{
private int myNumberField;
public int MyNumberField
{
get { return myNumberField; }
set
{
if (value >= 1 amp;amp; value <=3)
myNumberField = value;
else
// throw exception?
// set default-value (maybe 1)?
// do nothing?
}
}
}
вы могли бы делать все, что хотите, в установщике вашего свойства
и ограничивать его только во внешнем интерфейсе — не лучшее решение, поскольку вы всегда можете изменить javascript / html — но вы должны показать пользователю, что он может вставлять значения только 1, 2 или 3. Также ограничьте его в viewmodel аннотациями данных.
или:
вы также можете переопределить EntityFrameworks SaveChanges
и добавить свою businesslogic:
public override int SaveChanges(SaveOptions options)
{
foreach (ObjectStateEntry entry in
ObjectStateManager.GetObjectStateEntries(
EntityState.Added | EntityState.Modified))
{
// Validate the objects in the Added and Modified state
// if the validation fails, e.g. throw an exeption.
}
return base.SaveChanges(options);
}