Entity Framework mapping - PullRequest
       6

Entity Framework mapping

1 голос
/ 29 июля 2011

Я создал простые классы, которые имитируют классы, которые у меня есть (извините, мне пришлось составить классы, обычные примерные базы данных не имеют структуры, о которой я хотел спросить):

public class Animal
{  
    public System.Guid ID { get; set; }
    public string SpeciesName { get; set; }  
    public virtual ICollection<AnimalSpecies> AnimalSpecies { get; set; }
}

Вид рыбы:

public class Fish 
{     
    public System.Guid ID { get; set; }
    public int Freshwater { get; set; } 
}

Spieces Reptile:

public class Reptile
{     
    public System.Guid ID { get; set; }
    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 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.Property(t => t.Animal_ID).HasColumnName("Animal_ID");
    this.Property(t => t.Spieces_ID).HasColumnName("Spieces_ID");

    // Relationship between Animal and AnimalSpieces: 
    this.HasRequired(t => t.Animal)
            .WithMany(t => t.AnimalSpecies)
            .HasForeignKey(d => d.Animal_ID);               
}

Так как Spieces_ID не имеет внешнего ключа, есть ли способ сопоставить отношения между AnimalSpecies и Fish / Reptile?

1 Ответ

3 голосов
/ 28 августа 2011

Я не думаю, что можно определить отображение, где AnimalSpecies.Species_ID участвует в качестве внешнего ключа в двух разных отношениях - одно между AnimalSpecies и Fish и второе между AnimalSpecies и Reptile.

Мне кажется, что в вашей модели отсутствует базовый класс Species для Fish и Reptile. Если бы у вас был такой базовый класс, ваша модель могла бы выглядеть так:

public class Animal
{
    public System.Guid ID { get; set; }
    //...
    public virtual ICollection<AnimalSpecies> 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> 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; }
}

И отображение:

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);               
}

Если у вашего AnimalSpecies класса нет других членов, кроме клавиш и навигационных свойств, вы также можете удалить этот класс из модели и отобразить прямое отношение «многие ко многим» между Animal и Species (не Это не имеет смысла с точки зрения предметной области, потому что животное принадлежит только одному виду, не так ли?):

public class Animal
{
    public System.Guid ID { get; set; }
    //...
    public virtual ICollection<Species> Species { get; set; }
}

public class Species // I think the base class could also be abstract
{
    public System.Guid ID { get; set; }
    //...
    public virtual ICollection<Animal> 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

Отображение:

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 теперь является скрытой таблицей, которая управляется EF для отношения «многие ко многим» и не отображается в модели.

Я не уверен, правильно ли я понимаю ваш вопрос. Это как раз то, что пришло мне в голову.

Редактировать

Если вы не укажете никаких специальных отображений для производных классов, EF примет наследование TPH (Table-Per-Hierarchy), что означает, что все подклассы вместе с базовым классом хранятся в одной базе данных. таблица, отличающаяся столбцом дискриминатора.

Если у вас много производных классов со многими свойствами, то лучшей стратегией наследования может быть TPT (Table-Per-Type). В этом случае вы определяете для каждого подкласса свою собственную таблицу в отображении:

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

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

Теперь каждый производный класс получает свою собственную таблицу, а базовый класс хранится в таблице «Виды». EF создаст соответствующие объединения в базе данных при запросе рыбы, например:

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

Подробнее о различных стратегиях отображения наследования, их преимуществах и недостатках можно прочитать здесь:

...