2018年7月11日 星期三

[Entity Framework 6] Code First (5) - Relations


 Entity Framework   Code first    Relations  


Introduction


How to design code-first models for these relations

1.  One-to-one
2.  One-to-many
3.  Many-to-many



Environment


Entity Framework 6.2.0



Implement


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,



Reference



沒有留言:

張貼留言