C
C#2y ago
Strawby

❔ Generic entity type in EF Core

Heya everyone! GuraWave2 the recommended way to work with entities that have a property with a generic type on them? e.g:
internal sealed class MetricsEntity<TMetric> : Entity
where TMetric : class
{
public TMetric Data { get; set; } = default!;
}
internal sealed class MetricsEntity<TMetric> : Entity
where TMetric : class
{
public TMetric Data { get; set; } = default!;
}
I'd like to serialize and deserialize the data as JSON with a config that looks something like this: (I don't need to query the JSON data in the db)
internal sealed class MetricEntityConfiguration<TMetric> : IEntityTypeConfiguration<MetricsEntity<TMetric>>
where TMetric : class
{
public void Configure(EntityTypeBuilder<MetricsEntity<TMetric>> builder)
{
builder.ToTable(MetricTableNames.Metric, MetricTableNames.SchemaName);
builder.HasKey(x => x.Id);
builder.OwnsOne(x => x.Data, b => b.ToJson());
}
}
internal sealed class MetricEntityConfiguration<TMetric> : IEntityTypeConfiguration<MetricsEntity<TMetric>>
where TMetric : class
{
public void Configure(EntityTypeBuilder<MetricsEntity<TMetric>> builder)
{
builder.ToTable(MetricTableNames.Metric, MetricTableNames.SchemaName);
builder.HasKey(x => x.Id);
builder.OwnsOne(x => x.Data, b => b.ToJson());
}
}
Sadly though, that doesn't seem to work as I get an error saying: The entity type 'MetricsEntity<TestMetricData>' was not found. (I do have the model builder configured to use all type builders of the assembly) What's the preferred way to implement this? confuseddog
- Do I dynamically add a type configuration for all constructed generic types using reflection? - Do I change the property to be a string and serialize / deserialize it myself? - Do I do something entirely different? :0
25 Replies
Dusty
Dusty2y ago
I wouldn't know how that should work cause ef core would need to generate the table's on the fly for each generic type. I'd just use json, store that in the db and deserialize it via a property or Method on the class
Anton
Anton2y ago
how are you running the configuration classes?
Strawby
StrawbyOP2y ago
Haha, well. I don't know that either. I was hoping efcore had some magic baked into it that would allow it to store both the type and the serialized data in a field and then serialize and deserialize that data for you shrug Maybe something like table per hirarchy but without any additional fields doggoconfusedd just adding all configurations of the assembly to the model builder:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(AssemblyReference.Assembly);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(AssemblyReference.Assembly);
}
Anton
Anton2y ago
try calling the methods from resolved generic classes ah hold on MetricTableNames.Metric would be the same for all types in the generic, no? they have to be unique since the tables will have different column types
Strawby
StrawbyOP2y ago
Yeah, and I wouldn't know how efcore would handle table / property mapping in general since you've got multiple configurations with essentially the same type
Anton
Anton2y ago
that's fine as long as you run the configuration manually but the table name being the same won't work
Strawby
StrawbyOP2y ago
I'm not too stoked about it but I'll prolly have to go with smth like this
internal sealed class MetricsEntity : Entity
{
public string DataAsJson { get; set; } = default!;
public Type MetricType { get; set; } = default!;
}
internal sealed class MetricsEntity : Entity
{
public string DataAsJson { get; set; } = default!;
public Type MetricType { get; set; } = default!;
}
Anton
Anton2y ago
are these dynamic datatypes or something? can't you make a table for each and it won't be able to store the type I'd guess the best way I guess would be to make an interface for each metric type, and then implement it by the entity then just find these types by reflection if you can't list them manually make like an interface IMetric, make them all implement that, and then find all classes implementing that interface and configure them as entities you can also use owned types configured fluently
Strawby
StrawbyOP2y ago
Hmm yeah would prolly have to do some table per type thingy.. I'll have to see how efcore behaves if I register multiple configs with the same generic type definition but other arguments shrug Maybe I'll still need to make a constructed type for each. I Could probably dynamically create them but that seems like a really bad workaround
Anton
Anton2y ago
then you don't have to make no interfaces
Strawby
StrawbyOP2y ago
That'd need me to register them manually though, no? I'd rather not keep track of that :p
Anton
Anton2y ago
you can just create an entity for each type fluently without the actual entity class, then fluently configure them to own a metric thus you'll be able to use a metric as an entity I'm not sure what you'd do with the ids in this case just leave them managed automatically i guess ef core should be able to manage via shadow properties
Strawby
StrawbyOP2y ago
I might just serialize the data myself for now and just track the type with the entity. Seems like the feasible solution without having to create tons of tables that I'm not really gonna need for now. Like I said, I don't actually want to query the data, just retrieve a list of all "metrics" of a certain type. So that should work well enough for now Shrug
Anton
Anton2y ago
well you have to either list them somewhere, or make them implement an interface, or mark them with an attribute, or some combination of these I don't think you can store System.Type in a database
Strawby
StrawbyOP2y ago
Yeah I'd serialize it to the full name in the current assembly
Anton
Anton2y ago
you'll either have to manage conversions, or make a tag enum
Strawby
StrawbyOP2y ago
Shouldn't be too bad if the name of a type were to change, would just leave some junk in the db or I'd have to manually clean that up.. I could prolly live with that
Anton
Anton2y ago
you won't be using the db to the fullest like that but it's fine for prototyping I guess
Strawby
StrawbyOP2y ago
I mean, I can still look into a type per table solution once I actually have to query trough the data but as long as that'd not the case that doesn't seem worth the extra effort. Also, the data being stored there is really short lived e.g. will be updated every few hours so having some inconsistencies with the serialized type doesn't seem like a huge issue to me think
Anton
Anton2y ago
you could just store them in memory too
Strawby
StrawbyOP2y ago
That was the initial idea but the data is fetched by a "cron job" from a different container and needs to be persisted somewhere for a different job to pick up. We could look into just caching that as raw json in smth like redis but there's no redis instance for that deployment right now and I'm supposed to use the db if I needed to persist data
Anton
Anton2y ago
ah ok
Strawby
StrawbyOP2y ago
I think I've got a pretty good idea what to do now. Thanks for your insights! <a:neko_nod:819942443481825350>
Anton
Anton2y ago
np
Accord
Accord2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server