Generate migrations for new tables - c#

I just created a model with some database structures I'd like to created
namespace Ability.Models
{
public class Skill
{
[key]
public int ID { get; set; }
public string SkillName { get; set; }
public virtual List<Teacher> Teachers { get; set; }
}
public class Teacher
{
[key]
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Campus { get; set; }
public virtual List<Skill> Skills { get; set; }
}
public partial class AbilityDbContext : DbContext
{
public AbilityDbContext()
: base("name= DefaultConnection")
{
}
public virtual DbSet<Teacher> Teachers { get; set; }
public virtual DbSet<Skill> Skills { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Teacher>()
.HasMany(s => s.Skills)
.WithMany(c => c.Teachers);
base.OnModelCreating(modelBuilder);
}
}
}
However I have no idea how I can generate the migrations for these new tables. I thought it would give me a message when I try to Update-Database, so that I could use Add-Migration, but it just says
No pending explicit migrations.
So my question is, how can I let the Entity framework do the work for me and create the correct migrations?

Run the below commands in package manager console from visual studio under Tools menu item in order to have migration work
enable-migrations
add-migration AddTeacher
add-migration AddSkill
update-database
Also, if those entities are added new then you need to decorate them with Table attribute like
[System.ComponentModel.DataAnnotations.Schema.Table("Skills")]
public class Skill
{
[key]
public int ID { get; set; }
public string SkillName { get; set; }
public virtual List<Teacher> Teachers { get; set; }
}
[System.ComponentModel.DataAnnotations.Schema.Table("Teachers")]
public class Teacher
{
[key]
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Campus { get; set; }
public virtual List<Skill> Skills { get; set; }
}

Related

Define relationship in EF Core

How do I define the relationships here with EF Core?
I have an Employee table which has multiple Jobs
public class Employee
{
public int EmployeeId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public List<HourlyRate> DefaultRate { get; set; }
public string Note { get; set; }
public bool Active { get; set; }
public DateTime DateHired { get; set; }
public List<PhoneNumber> PhoneNumbers { get; set; }
public List<Address> Addresses { get; set; }
public List<Job> Jobs { get; set; }
public bool Deleted { get; set; }
}
And the Job class has an Employee object to navigate back to the employee and the Job has multiple Directors which are also Employees
public class Job
{
public int JobId { get; set; }
public Employee Employee { get; set; }
public JobType Type { get; set; }
public Department Department { get; set; }
public List<Employee> Directors { get; set; }
public bool Active { get; set; }
public decimal HourlyRate { get; set; }
public string Note { get; set; }
public bool Deduction { get; set; }
public int? DeductionPercent { get; set; }
}
This is my DbContext:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Employee>()
.HasMany(employee => employee.Jobs)
.WithOne(i => i.Employee);
}
Initially the Job only had a single Director and everything was good but the requirement has changed to have multiple directors and ef removed the Director column from the Job table and added a JobId column to the Employee table but the problem is that if i add that director to a second job by job.Directors.Add(director) EF overrides the job id of the of the director and the director is being removed from the previous job
I am using EF Core 2.2
if a Job has only 1 Employee but multiple Directors (also Employee)
add public int EmployeeId {get; set;} to your Job class and add this
modelBuilder
.Entity<Job>()
.HasMany(p => p.Directors)
.WithMany(p => p.Jobs));
also, change List<> to ICollection<>
You should tell EF through fluent API that there's a 1-to-many relationship from Employee to Job. Otherwise, EF may get confused.
The many-to-many relationship needs a junction table and matching entity in the model which you'll also need to configure through fluent API. You'll define two 1-to-many relationships from Employee and Job to that new entity. EF core does not directly support such relationships before 5.0.
If you are targeting SQL, then you need to mark at least one of the relationships as OnDelete(CascadeBehavior.NoAction). Otherwise, your model will generate invalid table defintions which will raise errors at creation time.
Update:
The junction table would be defined something like this.
public class Employee
{
// ... other stuff
public List<EmployeeJob> EmployeeJobs { get; set; }
}
public class Job
{
// ... other stuff
public List<EmployeeJob> EmployeeJobs { get; set; }
}
public class EmployeeJob
{
public int EmployeeId { get; set; }
public int JobId { get; set; }
public Employee Employee { get; set; }
public Job Job { get; set; }
}
// goes in DbContext
modelBuilder.Entity<EmployeeJob>.HasKey(x => new { x.EmployeeId, x.JobId });
Try to use this code. Since your employee can have one or many jobs I added the table EmployeeJob and many-to-many relations. I think you just need to add IsDirector flag to Employee or maybe better something like an EmployeeType:
public class Employee
{
public Employee()
{
EmployeeJobs = new HashSet<EmployeeJob>();
}
[Key]
public int EmployeeId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Note { get; set; }
public bool Active { get; set; }
public DateTime DateHired { get; set; }
public bool Deleted { get; set; }
[InverseProperty(nameof(EmployeeJob.Employee))]
public virtual ICollection<EmployeeJob> EmployeeJobs { get; set; }
}
public class Job
{
public Job()
{
EmployeeJobs = new HashSet<EmployeeJob>();
}
[Required]
public int JobId { get; set; }
public bool Active { get; set; }
public decimal HourlyRate { get; set; }
public string Note { get; set; }
public bool Deduction { get; set; }
public int? DeductionPercent { get; set; }
[InverseProperty(nameof(EmployeeJob.Job))]
public virtual ICollection<EmployeeJob> EmployeeJobs { get; set; }
}
public class EmployeeJob
{
[Key]
public int Id { get; set; }
public int EmployeeId { get; set; }
[ForeignKey(nameof(EmployeeId))]
[InverseProperty(nameof(EmployeeJob.Employee.EmployeeJobs))]
public virtual Employee Employee { get; set; }
public int JobId { get; set; }
[ForeignKey(nameof(JobId))]
[InverseProperty(nameof(EmployeeJob.Employee.EmployeeJobs))]
public virtual Job Job { get; set; }
}
public class EmployeeDbContext : DbContext
{
public EmployeeDbContext()
{
}
public EmployeeDbContext(DbContextOptions<EmployeeDbContext> options)
: base(options)
{
}
public DbSet<Employee> Employees { get; set; }
public DbSet<Job> Jobs { get; set; }
public DbSet<EmployeeJob> EmployeeJobs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(#"Server=localhost;Database=Employee;Trusted_Connection=True;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<EmployeeJob>(entity =>
{
entity.HasOne(d => d.Employee)
.WithMany(p => p.EmployeeJobs)
.HasForeignKey(d => d.EmployeeId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_EmployeeJob_Employee");
entity.HasOne(d => d.Job)
.WithMany(p => p.EmployeeJobs)
.HasForeignKey(d => d.JobId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_EmployeeJob_Job");
});
}

Table per Type in Entity Framework Core 2.0

These are my models:
public class Company
{
public int CompanyId { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Email { get; set; }
public string Url { get; set; }
//...
}
public class HeadOffice : Company
{
public int HeadOfficeId { get; set; }
public virtual List<BranchOffice> BranchOffice { get; set; } = new List<BranchOffice>();
}
public class BranchOffice : Company
{
public int BranchOfficeId { get; set; }
public virtual HeadOffice HeadOffice { get; set; }
}
I wanted the following database structure:
Table Company
CompanyId (PK)
Name
Address
Email
Url
Table HeadOffice
HeadOfficeId (PK)
CompanyId (FK)
Table BranchOffice
BranchOfficeId (PK)
HeadOfficeId (FK)
CompanyId (FK)
How can I do this?
When I create this migration, the EF creates just one table, with all columns! I don't want this approach!
You would have to change your Model to look like this, note that you can't use inheritance using this approach:
public class Company
{
public int CompanyId { get; set; }
//...
}
public class Company
{
public int CompanyId { get; set; }
public string Name { get; set; }
//...
}
public class HeadOffice
{
[ForeignKey(nameof(Company))]
public int CompanyId { get; set; }
public Company Company { get; set; }
// Add Properties here
}
public class BranchOffice
{
[ForeignKey(nameof(Company))]
public int CompanyId { get; set; }
public Company Company { get; set; }
// Add Properties here
}
Your DbContext:
public class YourContext : DbContext
{
public DbSet<Company> Companys { get; set; }
public DbSet<HeadOffice> HeadOffices { get; set; }
public DbSet<BranchOffice> BranchOffices { get; set; }
public YourContext(DbContextOptions<YourContext> options)
: base(options)
{
}
}
You could then use EF Core Migrations. The command would look somewhat like this:
dotnet ef migrations add Initial_TPT_Migration -p ./../../ModelProject.csproj -s ./../../ModelProject.csproj -c YourContext -o ./TptModel/CodeFirst/Migrations
It generats a Class Initial_TPT_Migration that contains methods to generate your database.
Usage
To query you would need to map Company Properties to the fieldnames. If you combine this with the Repository Pattern (link), it could actually be as convenient as the default approach in EF Core currently is to use.
YourContext ctx = ...
// Fetch all BranchOffices
var branchOffices = ctx.BranchOffices
.Select(c => new BranchOffice()
{
CompanyId = c.CompanyId,
Name = c.Company.Name,
})
.ToList();
You can find more informations about this approach here.
You can find an answer here https://learn.microsoft.com/en-us/aspnet/core/data/ef-mvc/inheritance?view=aspnetcore-2.1
Also check this topic out if you need many inherited classes against one table
https://learn.microsoft.com/en-us/ef/core/modeling/relational/inheritance
Copying the code here just in case microsoft used to mess with urls and docs
Each inherited type per table
public class SchoolContext : DbContext
{
public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
{
}
public DbSet<Student> Students { get; set; }
public DbSet<Instructor> Instructors { get; set; }
public DbSet<Person> People { get; set; }
protected override void OnModelCreating(ModelBuilder b)
{
b.Entity<Student>().ToTable("Student");
b.Entity<Instructor>().ToTable("Instructor");
b.Entity<Person>().ToTable("Person");
}
}
public abstract class Person
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
}
public class Instructor : Person
{
public DateTime HireDate { get; set; }
}
public class Student : Person
{
public DateTime EnrollmentDate { get; set; }
}
Many inherited types in one table
public class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasDiscriminator<string>("blog_type")
.HasValue<Blog>("blog_base")
.HasValue<RssBlog>("blog_rss");
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
public class RssBlog : Blog
{
public string RssUrl { get; set; }
}

ASP.NET MVC customer portal User Junction Table

Im building a management portal for a chain of restaurants. I am using ASP.NET MVC with EF Code First.
I want each user to, after login, only see the rescources that are connected to them. I want to put a junction table(many-to-many) between ApplicationUser and the Restaurant-class(model), since each user can have/work at many restaurants, and each restaurant can have many owners/workers.
How do you do this in EF Code first? The same way I did Restaurant --> Menue? Do you need to build a new DBContext for Applicationuser for this to work?
public class Restaurant
{
public int Id { get; set; }
public string Name { get; set; }
public string Adress { get; set; }
public string PhoneNumber { get; set; }
public DateTime StartDate { get; set; }
//Connections
public virtual ICollection<Menue> Menues { get; set; }
}
public class Menue
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public DateTime ModifyDate { get; set; }
//FK For RestaurantConnection
public int RestaurantId { get; set; }
}
For many to many configuration do like this
Student class should have a collection navigation property for Course, and Course should have a collection navigation property for student
public class Student
{
public Student()
{
this.Courses = new HashSet<Course>();
}
public int StudentId { get; set; }
[Required]
public string StudentName { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}
public class Course
{
public Course()
{
this.Students = new HashSet<Student>();
}
public int CourseId { get; set; }
public string CourseName { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
In your DbContext add this configuration
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>()
.HasMany<Course>(s => s.Courses)
.WithMany(c => c.Students)
.Map(cs =>
{
cs.MapLeftKey("StudentRefId");
cs.MapRightKey("CourseRefId");
cs.ToTable("StudentCourse");
});
}
For more information read this article Configure Many-to-Many relationship

How can I configure many-to-many relationship to my own created entity in entity framework

I have some classes:
public class Values : Entity
{
[Key]
public int Values_ID { get; set; }
[Required]
public string Values_Name { get; set; }
[Required]
public int ValuesNumeric { get; set; }
public virtual ICollection<ValuesMetrics> ValuesMetrics { get; set; }
}
public class GQMetric : Entity
{
[Key]
public int GQMetric_ID { get; set; }
[Required]
public string GQMetricName { get; set; }
[Required]
public int Importance_ID { get; set; }
public virtual List<GQMetricsQuestions> GQMetricsQuestions { get; set; }
public virtual ICollection<ValuesMetrics> ValuesMetrics { get; set; }
public virtual ImportanceScale ImportanceScale { get; set; }
}
I need to create many-to-many relationship to my own created class ValuesMetrics, not to automatically generated table by entity framework. I have tried a lot of solutions here, here and here but none of it did not work. Eventually, I did this:
public class ValuesMetrics : Entity
{
public int GQMetric_ID { get; set; }
public int Value_ID { get; set; }
public virtual GQMetric GQMetric { get; set; }
public virtual Values Values { get; set; }
}
FluentAPI:
modelBuilder.Entity<ValuesMetrics>()
.HasKey(c => new { c.GQMetric_ID, c.Value_ID });
modelBuilder.Entity<GQMetricsQuestions>()
.HasKey(c => new { c.GQMetric_ID, c.Question_ID });
but created table (ValuesMetrics) have an excessive relationship (GQMetrics_GQMetric_ID). I need only two primary keys from Values and GQMetrics tables
Can you advice me how to solve this problem? Thanks for any help!
Applied #Esteban 's solution from the link already referenced by you: Create code first, many to many, with additional fields in association table
Basically I did the following three changes:
Used POCO entities instead of inheriting from Entity class
Removed EF attributes, since we'll be using fluent API anyway
Changed fluent API configuration
Resulting code:
public class MyContext : DbContext
{
public DbSet<Values> Values { get; set; }
public DbSet<GQMetric> GqMetric { get; set; }
public DbSet<ValuesMetrics> ValuesMetrics { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Values>().HasKey(values => values.Values_ID);
modelBuilder.Entity<GQMetric>().HasKey(metric => metric.GQMetric_ID);
modelBuilder
.Entity<ValuesMetrics>()
.HasKey(valuesMetrics => new
{
valuesMetrics.Value_ID,
valuesMetrics.GQMetric_ID
});
modelBuilder
.Entity<ValuesMetrics>()
.HasRequired(valuesMetrics => valuesMetrics.Values)
.WithMany(valueMetrics => valueMetrics.ValuesMetrics)
.HasForeignKey(valueMetrics => valueMetrics.Value_ID);
modelBuilder
.Entity<ValuesMetrics>()
.HasRequired(valuesMetrics => valuesMetrics.GQMetric)
.WithMany(valueMetrics => valueMetrics.ValuesMetrics)
.HasForeignKey(valueMetrics => valueMetrics.GQMetric_ID);
base.OnModelCreating(modelBuilder);
}
}
public class Values
{
public int Values_ID { get; set; }
public string Values_Name { get; set; }
public int ValuesNumeric { get; set; }
public virtual ICollection<ValuesMetrics> ValuesMetrics { get; set; }
}
public class GQMetric
{
public int GQMetric_ID { get; set; }
public string GQMetricName { get; set; }
public virtual ICollection<ValuesMetrics> ValuesMetrics { get; set; }
}
public class ValuesMetrics
{
public int GQMetric_ID { get; set; }
public int Value_ID { get; set; }
public virtual GQMetric GQMetric { get; set; }
public virtual Values Values { get; set; }
}

Entity framework(Code first) - & ASP.net Membership Provider

I am currently trying to build a new application using EF6 Code First, I manage to create the database based on my models no problem.
Now what I want to do is use asp.net membership features. So I will have to have the database schema inside my database.
How can I do this?
There is information around the internet on using the simplemembershipprovider with EF, but it is very confusing.
Just so you have an idea of what I have done so far...(below)
So what is the best way to use membership with EF?
namespace AsoRock.Data.DTOs
{
public class Customer
{
[Key]
public int CustomerId { get; set; }
public string Title { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string HomeNumber { get; set; }
public string MobileNumber { get; set; }
public string Gender { get; set; }
public DateTime Dob { get; set; }
}
public class Order
{
[Key]
public int OrderId { get; set; }
public Address Address { get; set; }
public Customer Customer { get; set; }
public List<Product> Products { get; set; }
}
public class Product
{
[Key]
public int ProductId { get; set; }
public string ProductName { get; set; }
public decimal ProductPrice { get; set; }
}
public class Address
{
[Key]
public int AddressId { get; set; }
public Customer Customer { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
public string PostCode { get; set; }
public string LastUsed { get; set; }
public bool isDefault { get; set; }
}
public class AsoRockContext : DbContext
{
public DbSet<Customer> Customers { get; set; }
public DbSet<Address> Addresses { get; set; }
public DbSet<Order> Orders { get; set; }
// public DbSet<Product> Products { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>().HasMany(p => p.Products).WithMany().Map(m =>
{
m.MapLeftKey("OrderId").MapRightKey("ProductId").ToTable("OrderdProducts");
});
base.OnModelCreating(modelBuilder);
}
}
}
If you are using MVC 5 then you can change your
public class AsoRockContext : DbContext
to be
public class AsoRockContext : IdentityDbContext<ApplicationUser>
Then create your ApplicationUser
public class ApplicationUser : IdentityUser
{ //You can add extra properties in if you want
public string FirstName { get; set; }
public string LastName { get; set; }
//Or add a link to your customer table
public Customer CustomerDetails { get; set; }
}
Asp.net MVC 4+ comes with asp.net membership provider.
So you context name is TestConnection then
in the AccountModel in Model Directory, Change the defaultConnection to TestConnection
like this, then it will create membership table in your DB.
public UsersContext()
: base("TestConnection")
{
}
to know more about how it is achieve see the code, see the AccountController file and find the following in top
[InitializeSimpleMembership]
public class AccountController : Controller
Inspect the [InitializeSimpleMembership] attribute to learn how it is implemented.

Categories

Resources