Reputation: 9356
If I have a domain model that looks something like this:
public class Foo<T> {
public Guid Id { get; set; }
public string Statement { get; set; }
public T Value { get; set; }
}
I want to use it for built in Data Types (string, int, etc...) as well as date. I want to use it like:
var foo = new Foo<string>();
foo.Value = "Hey";
how can I persist this to a database using EF Core?
I imagine the database table would look like
| Id | Statement | ValueAsString | ValueAsDecimal | ValueAsDate | ValueAsInt |
| 1 | NULL | "Hey" | | | |
| 2 | NULL | | 1.1 | | |
Upvotes: 15
Views: 20292
Reputation: 383
If you want to persist different values types to the database in a single table similar to the one in your question, you can do it like this:
public interface IHasValue<T> {
T Value { get; set; }
}
public abstract class Foo {
public Guid Id { get; set; }
public string Statement { get; set; }
}
public class Foostring : Foo, IHasValue<string> {
string Value { get; set; }
}
public class FooInt : Foo, IHasValue<int> {
int Value { get; set; }
}
In your DbContext
class add properties:
public DbSet<FooString> FooStrings { get; set: }
public DbSet<FooInt> FooInts { get; set; }
You can set the column names for the table in the OnModelCreating
method of your DbContext
:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// include the base class so a single table is created for the hierarchy
// rather than a table for each child class
modelBuilder.Entity<Foo>().ToTable("Foos");
// Specify the column names or you will get weird names
modelBuilder.Entity<FooString>().Property(entity => entity.Value)
.HasColumnName("ValueAsString");
modelBuilder.Entity<FooInt>().Property(entity => entity.Value)
.HasColumnName("ValueAsInt");
}
This code will generate a table Foos
with columns Id
, Statement
, Discriminator
, ValueAsString
and ValueAsInt
. More info on the Discrimiator
column can be found here
You still need to create a class for each Type/column you want to use for T
, I don't think you can get around that.
Upvotes: 18
Reputation: 1706
you should still have a class. Your class Foo
should be abstract.
So you would get":
public abstract class Foo<T> {
public Guid Id { get; set; }
public string Statement { get; set; }
public T Value { get; set; }
}
then your implementation class would be:
public class Orders: Foo<Order> {
}
now you have your Orders
class with your generic type which can be stored.
Upvotes: 11