Entity Framework mapping

后端 未结 1 2013
甜味超标
甜味超标 2020-12-22 04:26

I\'ve made simple classes that simulate the classes I have (sorry I had to make up the classes, the usual example databases do not have the structure I wanted to ask about):

1条回答
  •  失恋的感觉
    2020-12-22 04:38

    I don't think that it's possible to define a mapping where AnimalSpecies.Species_ID participates as the foreign key in two different relationships - one between AnimalSpecies and Fish and a second between AnimalSpecies and Reptile.

    For me it looks like your model is missing a Species base class for Fish and Reptile. If you would have such a base class your model could look like this:

    public class Animal
    {
        public System.Guid ID { get; set; }
        //...
        public virtual ICollection AnimalSpecies { get; set; }
    }
    
    public class Species // I think the base class could also be abstract
    {
        public System.Guid ID { get; set; }
        //...
        public virtual ICollection AnimalSpecies { get; set; }
    }
    
    public class Fish : Species
    {
        public int Freshwater { get; set; } 
    }
    
    public class Reptile : Species
    {
        public int LifeExpectancy { get; set; }
    }
    
    public class AnimalSpecies
    {
        public System.Guid Animal_ID { get; set; }
        public System.Guid Species_ID { get; set; }
        public virtual Animal Animal { get; set; }
        public virtual Species Species { get; set; }
    }
    

    And the mapping:

    public AnimalSpeciesMap()
    {       
        this.HasKey(t => new { t.Animal_ID, t.Spieces_ID });
    
        this.Property(t => t.Animal_ID)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
        this.Property(t => t.Spieces_ID)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
    
        this.ToTable("AnimalSpecies");
    
        this.HasRequired(t => t.Animal)
            .WithMany(t => t.AnimalSpecies)
            .HasForeignKey(d => d.Animal_ID);               
    
        this.HasRequired(t => t.Species)
            .WithMany(t => t.AnimalSpecies)
            .HasForeignKey(d => d.Species_ID);               
    }
    

    If your AnimalSpecies class does not have other members than the keys and navigation properties you could also remove this class from the model and map a direct many-to-many relationship between Animal and Species (doesn't make sense from domain viewpoint because an animal belongs only to one species, does it?):

    public class Animal
    {
        public System.Guid ID { get; set; }
        //...
        public virtual ICollection Species { get; set; }
    }
    
    public class Species // I think the base class could also be abstract
    {
        public System.Guid ID { get; set; }
        //...
        public virtual ICollection Animals { get; set; }
    }
    
    public class Fish : Species
    {
        public int Freshwater { get; set; } 
    }
    
    public class Reptile : Species
    {
        public int LifeExpectancy { get; set; }
    }
    
    // no AnimalSpecies class anymore
    

    Mapping:

    public AnimalMap()
    {       
        this.HasMany(a => a.Species)
            .WithMany(s => s.Animals)
            .Map(x =>
            {
                x.MapLeftKey("Animal_ID");
                x.MapRightKey("Species_ID");
                x.ToTable("AnimalSpecies");
            });
    }
    

    AnimalSpecies is now a hidden table which is managed by EF for the many-to-many relationship and not exposed in the model.

    I am not sure if I understand your question correctly. This is just what came to my mind.

    Edit

    If you don't specify any special mappings for the derived classes EF will assume TPH (Table-Per-Hierarchy) inheritance which means that all subclasses together with the base class are stored in the same database table, distinguished by a discriminator column.

    If you have many derived classes with many properties each the better inheritance strategy might be TPT (Table-Per-Type). In this case you define for each subclass its own table in the mapping:

    public FishMap()
    {
        this.ToTable("Fishes");
    }
    
    public ReptileMap()
    {
        this.ToTable("Reptiles");
    }
    

    Now every derived class gets its own table and the base class is stored in table "Species". EF will create the appropriate joins in the database when you query for a fish for example:

    var result = context.Species.OfType()   // Species is DbSet
        .Where(f => f.Freshwater == 1).ToList();
    

    You can read more about the different inheritance mapping strategies and their benefits and drawbacks here:

    • TPH: http://weblogs.asp.net/manavi/archive/2010/12/24/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-1-table-per-hierarchy-tph.aspx

    • TPT: http://weblogs.asp.net/manavi/archive/2010/12/28/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-2-table-per-type-tpt.aspx

    • TPC: http://weblogs.asp.net/manavi/archive/2011/01/03/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-3-table-per-concrete-type-tpc-and-choosing-strategy-guidelines.aspx

    0 讨论(0)
提交回复
热议问题