在 Entity Framework Core 中使用两列的一对多关系 [英] one-to-many relation using two columns in Entity Framework Core

查看:16
本文介绍了在 Entity Framework Core 中使用两列的一对多关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的项目中,我有一个表 Translation 可以对任何模型进行翻译.为此,该表具有两个字段:ModelModelId.Model 属性包含一个表示模型类型的整数,ModelId 具有此模型的 id.
因此,例如:Product 表具有模型类型 id 1.要获取 ID 为 317 的产品的所有翻译,我搜索带有 Model=1 AND ModelId=317 的翻译.

In my project I have a table Translation that can have translations for any model. To achieve this, the table has two fields: Model and ModelId. The Model property holds an integer indicating the type of the model and the ModelId has the id of this model.
So, for example: the Product table has modeltype id 1. To get all translations for a product with id 317, I search for translations with Model=1 AND ModelId=317.

现在我想在 Entity Framework Core 中创建这个关系.我的所有模型都继承自 BaseModel 类,该类具有一个属性 ModelType 保存模型类型的 id.此字段未映射,因此在数据库中不可用.

Now I would like to create this relation in Entity Framework Core. All my models inherit from the class BaseModel that has a property ModelType holding the id of the model type. This field is not mapped, so it is not available in the database.

我曾尝试使用 fluent api 创建关系,但它不允许我指定更多要过滤的列.

I have tried to create the relation using fluent api, but it doesn't allow me to specify more columns to filter on.

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

有没有什么方法可以创建这种关系,而不必为每个需要翻译的查询手动创建连接?

Is there any way to create this relation without having to manually create a join for every query that requires translations?

推荐答案

既然 modelBuilder.Entity() 将使用 TPH 继承方式,我假设你是不使用 EF 代码优先方法创建数据库,而是使用它来将模型映射到现有数据库.然后你可以尝试这样的事情:

Since modelBuilder.Entity<BaseModel>() will use TPH inheritance approach, I assume you are not using EF code first approach for database creation and you are using it to map your models to an existing database. Then you can try something like this:

模型:

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

数据库上下文:

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 获取仅适用于当前模型类型的翻译.

As you can see you can use ModelTypeTranslations to get Translations only for current model type.

我应该注意到这种方法可能存在性能问题,因为它仅在内存中按 ModelType 过滤 Translations.我还尝试通过使用 lazy loading 来避免在内存中进行过滤 但我得到了 一些例外,即使我只是安装了那个包而不调用optionsBuilder.UseLazyLoadingProxies().我希望它会在下一个版本中修复.

I should note this approach may have performance issues since it filters Translations by ModelType only in memory. Also I tried to avoid filtering in memory by using lazy loading but I got some exception even if I just installed that package without invoking optionsBuilder.UseLazyLoadingProxies(). I hope it will be fixed in the next releases.

这篇关于在 Entity Framework Core 中使用两列的一对多关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆