问题描述
在我的项目中,我有一个表 Translation
,该表可以包含任何模型的翻译。为此,该表具有两个字段: Model
和 ModelId
。 Model
属性包含一个指示模型类型的整数,而 ModelId
具有此模型的ID。
例如: Product
表的模型类型ID为 1
。要获取ID为 317
的产品的所有翻译,我搜索 Model = 1和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.
我尝试使用流利的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< ; BaseModel>()
将使用 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; }
}
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。
As you can see you can use ModelTypeTranslations
to get Translations only for current model type.
我应该注意,这种方法可能会出现性能问题,因为它会按 ModelType 翻译
/ code>仅在内存中。另外,我还尝试通过使用,但是我得到了,即使我只是安装了该软件包而没有调用 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中使用两列的一对多关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!