Entity Framework Code first Relations
How to design code-first models for these
relations
1. One-to-one
2. One-to-many
3. Many-to-many
▋Entity Framework 6.2.0
Let’s see the final result as following,
Suppliers(供應商) 1 <-> 1
SupplierInCharges(供應商負責人)
Suppliers(供應商) 1 <-> 0..*
Factorys(工廠)
Suppliers(供應商) * <-> *
Customers(客戶)
▋1.Data Annotation
Attribute
▋One-to-one
[Table("Suppliers")]
public class Supplier
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
#region One-to-one
public virtual SupplierInCharge
InCharge { get; set; }
#endregion
}
[Table("SupplierInCharges")]
public class SupplierInCharge
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[ForeignKey("Supplier")]
public int Id { get; set; }
#region One-to-one
public virtual Supplier
Supplier { get; set; }
#endregion
}
Notice
that both the values of the primary keys in Suppliers and SupplierInCharges
will be the same when inserting an object:Supplier.
▋One-to-many
[Table("Suppliers")]
public class Supplier
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
#region One-to-many
public virtual ICollection<Factory>
Factorys { get; set; }
#endregion
}
[Table("Factorys")]
public class Factory
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public int
SupplierId { get; set; }
#region Many-to-one
[ForeignKey("SupplierId")]
public virtual Supplier
Supplier { get; set; }
#endregion
}
▋Many-to-many
[Table("Suppliers")]
public class Supplier
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
#region Many-to-many
public virtual ICollection<Customer>
Customers { get; set; }
#endregion
}
[Table("Customers")]
public class Customer
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
#region Many-to-many
public virtual ICollection<Supplier>
Suppliers { get; set; }
#endregion
}
▋2.Fluent API
We
will replace Data Annotation with Fluent API, so first we remove all data
annotations on the models.
▋Models
[Table("Suppliers")]
public class Supplier
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
#region One-to-one
public virtual SupplierInCharge
InCharge { get; set; }
#endregion
#region One-to-many
public virtual ICollection<Factory>
Factorys { get; set; }
#endregion
#region Many-to-many
public virtual ICollection<Customer>
Customers { get; set; }
#endregion
}
[Table("SupplierInCharges")]
public class SupplierInCharge
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
#region One-to-one
public virtual Supplier
Supplier { get; set; }
#endregion
}
[Table("Factorys")]
public class Factory
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public int
SupplierId { get; set; }
#region Many-to-one
public virtual Supplier
Supplier { get; set; }
#endregion
}
[Table("Customers")]
public class Customer
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[StringLength(100)]
public string Name { get; set; }
[StringLength(200)]
public string Address
{ get; set; }
#region Many-to-many
public virtual ICollection<Supplier>
Suppliers { get; set; }
#endregion
}
▋DbContext
public class AppDbContext : System.Data.Entity.DbContext
{
public AppDbContext()
: base("name=AppDbContext")
{
}
public DbSet<Supplier>
Suppliers { get; set; }
public DbSet<Factory>
Factorys { get; set; }
public DbSet<SupplierInCharge>
SupplierInCharges { get; set; }
public DbSet<Customer>
Customers { get; set; }
protected override void OnModelCreating(DbModelBuilder
modelBuilder)
{
#region
Relations
//One-to-one
modelBuilder.Entity<Supplier>().HasRequired(m =>
m.InCharge).WithRequiredPrincipal(m =>
m.Supplier);
//One-to-many
modelBuilder.Entity<Supplier>().HasMany(m =>
m.Factorys).WithRequired(m =>
m.Supplier);
//Many-to-many
modelBuilder.Entity<Supplier>()
.HasMany<Customer>(s
=> s.Customers)
.WithMany(c =>
c.Suppliers)
.Map(cs
=>
{
cs.MapLeftKey("SupplierId");
cs.MapRightKey("CustomerId");
cs.ToTable("SupplierCustomers");
});
#endregion
#region
Cascade setting
modelBuilder.Entity<Supplier>().HasRequired(i =>
i.InCharge)
.WithRequiredPrincipal(i =>
i.Supplier).WillCascadeOnDelete(true);
#endregion
}
}
Notice that we specified the column name on SupplierCustomers,
so the final table will be like this,