отношение один ко многим с использованием двух столбцов в Entity Framework Core - PullRequest
0 голосов
/ 27 апреля 2018

В моем проекте у меня есть таблица Translation, которая может иметь переводы для любой модели. Для этого в таблице есть два поля: Model и ModelId. Свойство Model содержит целое число, указывающее тип модели, а ModelId имеет идентификатор этой модели.
Так, например: таблица Product имеет идентификатор типа модели 1. Чтобы получить все переводы для продукта с идентификатором 317, я ищу переводы с Model=1 AND ModelId=317.

Теперь я хотел бы создать это отношение в Entity Framework Core. Все мои модели наследуются от класса BaseModel, который имеет свойство ModelType, содержащее идентификатор типа модели. Это поле не сопоставлено, поэтому оно не доступно в базе данных.

Я пытался создать отношение, используя свободный API, но он не позволяет мне указать больше столбцов для фильтрации.

modelBuilder.Entity<BaseModel>()
    .HasMany<Translation>(bm => bm.Translations)
    // Extra filters

Есть ли способ создать это отношение, не создавая вручную соединение для каждого запроса, требующего перевода?

Ответы [ 2 ]

0 голосов
/ 20 мая 2018

Поскольку modelBuilder.Entity<BaseModel>() будет использовать TPH подход наследования, я предполагаю, что вы не используете подход EF code first для создания базы данных, а используете его для сопоставления ваших моделей с существующей базой данных. Тогда вы можете попробовать что-то вроде этого:

Модели:

public class Translation
{
    public int Id { get; set; }
    public int Model { get; set; }
    public int ModelId { get; set; }
}

public class BaseModel
{
    public BaseModel(int modelType)
    {
        ModelType = modelType;
    }
    public int Id { get; set; }
    public int ModelType { get; set; }

    public ICollection<Translation> Translations { get; set; }// only for internal use
    public IEnumerable<Translation> ModelTypeTranslations
    {
        get
        {
            return this.Translations.Where(t => t.Model == this.ModelType);
        }
    }

}

public class SomeModel : BaseModel
{
    public SomeModel() : base(1) { }
    public int SomeProperty { get; set; }
}

public class AnotherModel : BaseModel
{
    public AnotherModel() : base(2) { }
    public int AnotherProperty { get; set; }
}

DbContext:

public class MyDbContext: DbContext
{
    ...

    public DbSet<Translation> Translations { get; set; }
    public DbSet<SomeModel> SomeModels { get; set; }
    public DbSet<AnotherModel> AnotherModels { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        ...
        modelBuilder.Entity<Translation>().HasKey(e => e.Id);

        var baseModelTypes = typeof(BaseModel).Assembly.GetExportedTypes()
            .Where(t => typeof(BaseModel).IsAssignableFrom(t) && t != typeof(BaseModel)).ToList();

        foreach (var type in baseModelTypes)
        {
            modelBuilder.Entity<Translation>().HasOne(type).WithMany(nameof(BaseModel.Translations)).HasForeignKey(nameof(Translation.ModelId));

            modelBuilder.Entity(type).Ignore(nameof(BaseModel.ModelType));
            modelBuilder.Entity(type).Ignore(nameof(BaseModel.ModelTypeTranslations));
            modelBuilder.Entity(type).HasKey(nameof(BaseModel.Id));
        }
    }
}

Как видите, вы можете использовать ModelTypeTranslations, чтобы получать переводы только для текущего типа модели.

Следует отметить, что у этого подхода могут быть проблемы с производительностью, поскольку он фильтрует Translations по ModelType только в памяти. Также я пытался избежать фильтрации в памяти, используя lazy loading, но получил некоторое исключение , даже если я только что установил этот пакет без вызова optionsBuilder.UseLazyLoadingProxies(). Я надеюсь, что это будет исправлено в следующих выпусках.

0 голосов
/ 18 мая 2018

Да, есть. Используйте это:

modelBuilder.Entity<BaseModel>()
.HasMany(bm => bm.Translations)
.WithForeignKey(x => new { x.Key1, x.Key2 });

Ключи1 и Ключ2, очевидно, должны быть ключами для отношения, и вам также может потребоваться определить их как таковые (в том же порядке) для сущности перевода.

...