Проверка данных
Примечание
ТОЛЬКО EF4.1 — функции, API и т. д., рассмотренные на этой странице, были представлены в Entity Framework 4.1. Если вы используете более раннюю версию, некоторые или все сведения не применяются.
Содержимое на этой странице адаптировано из статьи, первоначально написанной Джули Лерман (https://thedatafarm.com).
Entity Framework предоставляет множество функций проверки, которые могут передаваться в пользовательский интерфейс для проверки на стороне клиента или использоваться для проверки на стороне сервера. При использовании кода сначала можно указать проверки с помощью конфигураций заметок или свободного API. Дополнительные проверки и более сложные могут быть указаны в коде и будут ли работать модели от кода в первую очередь, модели в первую очередь или базы данных.
Я продемонстрировать проверки с простой парой классов: Блог и Post.
public class Blog
{
public int Id { get; set; }
public string Title { get; set; }
public string BloggerName { get; set; }
public DateTime DateCreated { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public DateTime DateCreated { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public ICollection<Comment> Comments { get; set; }
}
Код сначала использует заметки из System.ComponentModel.DataAnnotations
сборки в качестве одного из средств настройки первых классов кода. Среди этих заметок есть те, которые предоставляют такие правила, как Required
и MaxLength
MinLength
. Ряд клиентских приложений .NET также распознает эти заметки, например, ASP.NET MVC. С помощью этих заметок можно выполнить проверку на стороне клиента и сервера. Например, можно принудительно принудить свойство Title блога к обязательному свойству.
[Required]
public string Title { get; set; }
При отсутствии дополнительных изменений кода или разметки в приложении существующее приложение MVC будет выполнять проверку на стороне клиента, даже динамически создавая сообщение с помощью имен свойств и заметок.
В методе обратной передачи этого представления создания Entity Framework используется для сохранения нового блога в базе данных, но проверка на стороне клиента MVC активируется до того, как приложение достигнет этого кода.
Проверка на стороне клиента не является маркером проверки. Пользователи могут повлиять на функции браузера или еще хуже, хакер может использовать некоторые трюки, чтобы избежать проверок пользовательского интерфейса. Но Entity Framework также распознает заметку Required
и проверит ее.
Простой способ проверить это — отключить функцию проверки на стороне клиента MVC. Это можно сделать в файле веб-конфигурации приложения MVC. В разделе приложения Параметры есть ключ для ClientValidationEnabled. Если этот ключ задан как false, пользовательский интерфейс не будет выполнять проверки.
<appSettings>
<add key="ClientValidationEnabled"value="false"/>
...
</appSettings>
Даже если проверка на стороне клиента отключена, вы получите тот же ответ в приложении. Сообщение об ошибке "Поле заголовка является обязательным" будет отображаться как раньше. Кроме того, теперь это будет результатом проверки на стороне сервера. Entity Framework выполнит проверку заметки Required
(прежде чем даже беспокоить, чтобы создать INSERT
команду для отправки в базу данных) и возвратит ошибку MVC, которая отобразит сообщение.
Вы можете использовать простой API кода вместо заметок, чтобы получить ту же проверку на стороне клиента и сервера. Вместо использования, я показываю Required
вам это с помощью проверки MaxLength.
Конфигурации API Fluent применяются в качестве кода сначала создает модель из классов. Конфигурации можно внедрить, переопределив метод OnModelCreating класса DbContext. Ниже приведена конфигурация, указывающая, что свойство BlogName не может превышать 10 символов.
public class BlogContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
public DbSet<Comment> Comments { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>().Property(p => p.BloggerName).HasMaxLength(10);
}
}
Ошибки проверки, возникающие на основе конфигураций API Fluent, не будут автоматически достигать пользовательского интерфейса, но вы можете записать его в коде, а затем ответить на него соответствующим образом.
Ниже приведен код ошибки обработки исключений в классе BlogController приложения, который фиксирует ошибку проверки, когда Entity Framework пытается сохранить блог с именем блога, превышающим максимум 10 символов.
[HttpPost]
public ActionResult Edit(int id, Blog blog)
{
try
{
db.Entry(blog).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
catch (DbEntityValidationException ex)
{
var error = ex.EntityValidationErrors.First().ValidationErrors.First();
this.ModelState.AddModelError(error.PropertyName, error.ErrorMessage);
return View();
}
}
Проверка не автоматически передается в представление, поэтому используется дополнительный код, который используется ModelState.AddModelError
. Это гарантирует, что сведения об ошибке делают его в представлении, которое затем будет использовать ValidationMessageFor
Htmlhelper для отображения ошибки.
@Html.ValidationMessageFor(model => model.BloggerName)
IValidatableObject
— это интерфейс, который живет в System.ComponentModel.DataAnnotations
. Хотя он не является частью API Entity Framework, вы по-прежнему можете использовать его для проверки на стороне сервера в классах Entity Framework. IValidatableObject
Validate
предоставляет метод, который Entity Framework будет вызывать во время SaveChanges или вызывать себя в любое время, когда вы хотите проверить классы.
Такие конфигурации, как Required
и MaxLength
проверка в одном поле. В методе Validate
можно использовать еще более сложную логику, например сравнение двух полей.
В следующем примере Blog
класс был расширен для реализации IValidatableObject
, а затем укажите правило, которое Title
не BloggerName
удается сопоставить.
public class Blog : IValidatableObject
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
public string BloggerName { get; set; }
public DateTime DateCreated { get; set; }
public virtual ICollection<Post> Posts { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (Title == BloggerName)
{
yield return new ValidationResult(
"Blog Title cannot match Blogger Name",
new[] { nameof(Title), nameof(BloggerName) });
}
}
}
Конструктор ValidationResult
принимает string
сообщение об ошибке и массив string
s, представляющий имена членов, связанные с проверкой. Так как эта проверка проверка как именаBloggerName
, так Title
и имена свойств возвращаются.
В отличие от проверки, предоставленной API Fluent, этот результат проверки распознается представлением и обработчиком исключений, используемым ранее для добавления ошибки ModelState
в ненужную. Так как в поле "MVC HtmlHelpers" заданы оба имени ValidationResult
свойств, отображается сообщение об ошибке для обоих этих свойств.
DbContext
имеет переопределимый метод ValidateEntity
. При вызове SaveChanges
Entity Framework вызовет этот метод для каждой сущности в своем кэше, состояние которого не Unchanged
является. Логику проверки можно поместить непосредственно здесь или даже использовать этот метод для вызова, например метода, добавленного Blog.Validate
в предыдущем разделе.
Ниже приведен пример ValidateEntity
переопределения, который проверяет новые Post
версии, чтобы убедиться, что название записи еще не использовалось. Сначала проверка, чтобы узнать, является ли сущность записью и что его состояние добавлено. Если это так, то он выглядит в базе данных, чтобы узнать, есть ли уже запись с тем же заголовком. Если уже есть существующая запись, создается новое DbEntityValidationResult
.
DbEntityValidationResult
размещается и DbEntityEntry
ICollection<DbValidationErrors>
для одной сущности. В начале этого метода создается экземпляр, DbEntityValidationResult
а затем все обнаруженные ошибки добавляются в свою ValidationErrors
коллекцию.
protected override DbEntityValidationResult ValidateEntity (
System.Data.Entity.Infrastructure.DbEntityEntry entityEntry,
IDictionary<object, object> items)
{
var result = new DbEntityValidationResult(entityEntry, new List<DbValidationError>());
if (entityEntry.Entity is Post post && entityEntry.State == EntityState.Added)
{
// Check for uniqueness of post title
if (Posts.Where(p => p.Title == post.Title).Any())
{
result.ValidationErrors.Add(
new System.Data.Entity.Validation.DbValidationError(
nameof(Title),
"Post title must be unique."));
}
}
if (result.ValidationErrors.Count > 0)
{
return result;
}
else
{
return base.ValidateEntity(entityEntry, items);
}
}
Вызов SaveChanges
для активации всех проверок, описанных в этой статье. Но вам не нужно полагаться SaveChanges
. Вы можете выбрать проверку в другом месте приложения.
DbContext.GetValidationErrors
активирует все проверки, определенные заметками или API Fluent, проверку, созданную IValidatableObject
(например, Blog.Validate
) и проверки, выполняемые в методе DbContext.ValidateEntity
.
Следующий код вызовет GetValidationErrors
текущий экземпляр объекта DbContext
. ValidationErrors
группируются по типу DbEntityValidationResult
сущности. Код выполняет итерацию сначала по DbEntityValidationResult
значениям, возвращаемым методом, а затем через каждый из них DbValidationError
.
foreach (var validationResult in db.GetValidationErrors())
{
foreach (var error in validationResult.ValidationErrors)
{
Debug.WriteLine(
"Entity Property: {0}, Error {1}",
error.PropertyName,
error.ErrorMessage);
}
}
Ниже приведены некоторые другие моменты, которые следует учитывать при использовании проверки Entity Framework:
- Отложенная загрузка отключена во время проверки
- EF проверяет заметки данных в не сопоставленных свойствах (свойства, которые не сопоставлены со столбцом в базе данных)
- Проверка выполняется после обнаружения изменений во время
SaveChanges
. При внесении изменений во время проверки ответственность за уведомление средства отслеживания изменений DbUnexpectedValidationException
возникает при возникновении ошибок во время проверки- Аспекты, которые Entity Framework включают в модель (максимальная длина, обязательный и т. д.), приведет к проверке, даже если в классах нет заметок данных и (или) использовался конструктор EF для создания модели.
- Правила приоритета:
- Вызовы API Fluent переопределяют соответствующие заметки данных
- Порядок выполнения:
- Проверка свойств происходит перед проверкой типа
- Проверка типа возникает только в том случае, если проверка свойств завершается успешно
- Если свойство является сложным, его проверка также будет включать:
- Проверка уровня свойств для свойств сложного типа
- Проверка уровня типа для сложного типа, включая
IValidatableObject
проверку на сложном типе
API проверки в Entity Framework играет очень хорошо с проверкой на стороне клиента в MVC, но вам не нужно полагаться на проверку на стороне клиента. Entity Framework будет заботиться о проверке на стороне сервера для DataAnnotations или конфигураций, которые вы применили с кодом первый API Fluent.
Вы также видели ряд точек расширяемости для настройки поведения, используемого интерфейсом или касанием IValidatableObject
DbContext.ValidateEntity
метода. И эти два последних средства проверки доступны с помощью DbContext
рабочего процесса Code First, Model First или Database First для описания концептуальной модели.
Отзыв о .NET
.NET — это проект с открытым исходным кодом. Выберите ссылку, чтобы оставить отзыв: