Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use a generic type with entity framework core?

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            |             |            |
like image 975
chris31389 Avatar asked Oct 19 '17 08:10

chris31389


People also ask

How can I use generic type in C#?

A type parameter is a placeholder for a particular type specified when creating an instance of the generic type. A generic type is declared by specifying a type parameter in an angle brackets after a type name, e.g. TypeName<T> where T is a type parameter.

Should I use EF6 or EF core?

Keep using EF6 if the data access code is stable and not likely to evolve or need new features. Port to EF Core if the data access code is evolving or if the app needs new features only available in EF Core. Porting to EF Core is also often done for performance.

Can I use Entity Framework and dapper together?

To demonstrate the usage of Dapper, Entity Framework Core, and both combined, we will implement them each in the 3 Endpoints. For the GetAll Endpoints, we will use Dapper. The GetById Endpoint would use Entity Framework Core with Eager Loading to display the Department Details as well.

What is generic repository pattern in Entity Framework?

The generic repository pattern implements in a separate class library project. It uses the "Code First" development approach and creates a database from a model, using migration. This article demonstrates a sample Application, which has one too many relationships in ASP.NET Core with Entity Framework Core.


2 Answers

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.

like image 101
Roelant M Avatar answered Sep 18 '22 14:09

Roelant M


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

Image of the resulting table

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.

like image 27
Henk Kok Avatar answered Sep 17 '22 14:09

Henk Kok