Entity Framework - первый пример
Давайте определим очень простую модель с помощью классов. Мы просто определяем их в файле Program.cs, но в реальном приложении вы разделите свои классы на отдельные файлы и, возможно, в отдельный проект. Ниже приводится модель данных, которую мы будем создавать с использованием подхода Code First.
Создать модель
Добавьте следующие три класса в файл Program.cs, используя следующий код для класса Student.
public class Student {
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
Свойство ID станет столбцом первичного ключа таблицы базы данных, соответствующей этому классу.
Свойство Enrollments - это свойство навигации. Свойства навигации содержат другие сущности, связанные с этой сущностью.
В этом случае свойство Enrollments сущности Student будет содержать все сущности Enrollment, связанные с этой сущностью Student.
Свойства навигации обычно определяются как виртуальные, чтобы они могли использовать определенные функции Entity Framework, такие как отложенная загрузка.
Если свойство навигации может содержать несколько сущностей (как в отношениях «многие-ко-многим» или «один-ко-многим»), его типом должен быть список, в который можно добавлять, удалять и обновлять записи, например ICollection.
Ниже приведена реализация класса Course.
public class Course {
public int CourseID { get; set; }
public string Title { get; set; }
public int Credits { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
Свойство Enrollments - это свойство навигации. Сущность курса может быть связана с любым количеством сущностей регистрации.
Ниже приведена реализация класса и перечисления Enrollment.
public enum Grade {
A, B, C, D, F
}
public class Enrollment {
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public Grade? Grade { get; set; }
public virtual Course Course { get; set; }
public virtual Student Student { get; set; }
}
Свойство EnrollmentID будет первичным ключом.
Свойство Grade - это перечисление. Знак вопроса после объявления типа Grade означает, что свойство Grade допускает значение NULL.
Нулевая оценка отличается от нулевой оценки. Нулевое значение означает, что оценка неизвестна или еще не выставлена.
Свойства StudentID и CourseID являются внешними ключами, а соответствующие свойства навигации - Student и Course.
Сущность Enrollment связана с одной сущностью Student и одним курсом, поэтому свойство может содержать только одну сущность Student и Course.
Создать контекст базы данных
Основным классом, координирующим функциональность Entity Framework для данной модели данных, является класс контекста базы данных, который позволяет запрашивать и сохранять данные. Вы можете создать этот класс, унаследовав его от класса DbContext и предоставив типизированный DbSet
public class MyContext : DbContext {
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}
Ниже приведен полный код в файле Program.cs.
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EFCodeFirstDemo {
class Program {
static void Main(string[] args) {}
}
public enum Grade {
A, B, C, D, F
}
public class Enrollment {
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public Grade? Grade { get; set; }
public virtual Course Course { get; set; }
public virtual Student Student { get; set; }
}
public class Student {
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
public class Course {
public int CourseID { get; set; }
public string Title { get; set; }
public int Credits { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
public class MyContext : DbContext {
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}
}
Приведенный выше код - это все, что нам нужно для начала хранения и получения данных. Давайте добавим данные, а затем извлечем их. Ниже приведен код основного метода.
static void Main(string[] args) {
using (var context = new MyContext()) {
// Create and save a new Students
Console.WriteLine("Adding new students");
var student = new Student {
FirstMidName = "Alain", LastName = "Bomer",
EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
};
context.Students.Add(student);
var student1 = new Student {
FirstMidName = "Mark", LastName = "Upston",
EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
};
context.Students.Add(student1);
context.SaveChanges();
// Display all Students from the database
var students = (from s in context.Students
orderby s.FirstMidName select s).ToList<Student>();
Console.WriteLine("Retrieve all Students from the database:");
foreach (var stdnt in students) {
string name = stdnt.FirstMidName + " " + stdnt.LastName;
Console.WriteLine("ID: {0}, Name: {1}", stdnt.ID, name);
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
Когда приведенный выше код будет выполнен, вы получите следующий результат.
Adding new students
Retrieve all Students from the database:
ID: 1, Name: Alain Bomer
ID: 2, Name: Mark Upston
Press any key to exit...
Теперь возникает вопрос, где находятся данные и база данных, в которую мы добавили некоторые данные, а затем получили их из базы данных. По соглашению DbContext создал для вас базу данных.
Если доступен локальный экземпляр SQL Express, Code First создал базу данных на этом экземпляре.
Если SQL Express недоступен, Code First попытается использовать LocalDb.
База данных названа в честь полного имени производного контекста.
В нашем случае доступен экземпляр SQL Express, а имя базы данных - EFCodeFirstDemo.MyContext, как показано на следующем изображении.
Это просто соглашения по умолчанию, и есть различные способы изменить базу данных, которую использует Code First.
Как вы можете видеть на изображении выше, он создал таблицы «Студенты», «Курсы» и «Зачисление», и каждая таблица содержит столбцы с соответствующим типом данных и длиной.
Имена столбцов и тип данных также соответствуют свойствам соответствующих классов домена.
Инициализация базы данных
В приведенном выше примере мы видели, что Code First создает базу данных автоматически, но если вы хотите изменить имя базы данных и сервера, давайте посмотрим, как Code First определяет имя базы данных и сервер при инициализации базы данных. Взгляните на следующую диаграмму.
Вы можете определить базовый конструктор класса контекста следующими способами.
- Нет параметра
- Имя базы данных
- Имя строки подключения
Нет параметра
Если вы укажете базовый конструктор класса контекста без каких-либо параметров, как показано в приведенном выше примере, то инфраструктура сущностей создаст базу данных на вашем локальном сервере SQLEXPRESS с именем {Namespace}. {Context class name}.
В приведенном выше примере автоматически создаваемая база данных имеет имя EFCodeFirstDemo.MyContext. Если вы посмотрите на имя, вы обнаружите, что EFCodeFirstDemo - это пространство имен, а MyContext - это имя класса контекста, как показано в следующем коде.
public class MyContext : DbContext {
public MyContext() : base() {}
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}
Имя базы данных
Если вы передадите имя базы данных в качестве параметра в базовом конструкторе класса контекста, то Code First снова автоматически создаст базу данных, но на этот раз имя будет тем, которое было передано в качестве параметра в базовом конструкторе на локальном сервере базы данных SQLEXPRESS. .
В следующем коде MyContextDB указывается как параметр в базовом конструкторе. При запуске вашего приложения база данных с именем MyContextDB будет создана на вашем локальном сервере SQL.
public class MyContext : DbContext {
public MyContext() : base("MyContextDB") {}
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}
Имя строки подключения
Это простой способ указать DbContext использовать сервер базы данных, отличный от SQL Express или LocalDb. Вы можете поместить строку подключения в файл app.config.
Если имя строки подключения совпадает с именем вашего контекста (с квалификацией пространства имен или без нее), то оно будет найдено DbContext при использовании конструктора без параметров.
Если имя строки подключения отличается от имени вашего контекста, вы можете указать DbContext использовать это подключение в режиме Code First, передав имя строки подключения в конструктор DbContext.
public class MyContext : DbContext {
public MyContext() : base("name = MyContextDB") {}
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}
В приведенном выше коде фрагмент строки подключения класса контекста указан как параметр в базовом конструкторе.
Имя строки подключения должно начинаться с «name =», в противном случае оно будет рассматриваться как имя базы данных.
Эта форма явно указывает на то, что вы ожидаете, что строка подключения будет найдена в вашем файле конфигурации. Если строка подключения с данным именем не найдена, будет создано исключение.
<connectionStrings>
<add name = "MyContextDB"
connectionString = "Data Source =.;Initial Catalog = EFMyContextDB;Integrated Security = true"
providerName = "System.Data.SqlClient"/>
</connectionStrings>
Имя базы данных в строке подключения в app.config: EFMyContextDB. CodeFirst создаст новыйEFMyContextDB базу данных или использовать существующую EFMyContextDB база данных на локальном SQL Server.
Классы домена
Пока мы просто позволили EF обнаруживать модель, используя соглашения по умолчанию, но будут моменты, когда наши классы не следуют соглашениям, и нам нужно иметь возможность выполнять дальнейшую настройку. Но вы можете переопределить эти соглашения, настроив классы своей области для предоставления EF необходимой информации. Есть два варианта настройки классов вашего домена:
- Аннотации к данным
- Свободный API
Аннотации к данным
DataAnnotations используется для настройки ваших классов, которые выделяют наиболее часто используемые конфигурации. Аннотации данных также понимаются рядом приложений .NET, таких как ASP.NET MVC, которые позволяют этим приложениям использовать одни и те же аннотации для проверки на стороне клиента.
Ниже приведены аннотации данных, используемые в классе учащихся.
public class Enrollment {
[Key]
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public Grade? Grade { get; set; }
[ForeignKey("CourseID")]
public virtual Course Course { get; set; }
[ForeignKey("ID")]
public virtual Student Student { get; set; }
}
Свободный API
Большую часть конфигурации модели можно выполнить с помощью простых аннотаций к данным. Fluent API - это расширенный способ определения конфигурации модели, который охватывает все, что могут делать аннотации данных, в дополнение к более сложной конфигурации, невозможной с аннотациями данных. Аннотации к данным и свободный API можно использовать вместе.
Чтобы получить доступ к свободному API, вы переопределяете метод OnModelCreating в DbContext. Теперь давайте переименуем имя столбца в таблице учеников с FirstMidName на FirstName, как показано в следующем коде.
public class MyContext : DbContext {
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Entity<Student>().Property(s ⇒ s.FirstMidName)
.HasColumnName("FirstName");
}
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Enrollment> Enrollments { get; set; }
public virtual DbSet<Student> Students { get; set; }
}