Я не думаю, что можно определить отображение, где 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();
Подробнее о различных стратегиях отображения наследования, их преимуществах и недостатках можно прочитать здесь: