Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Composite-Type not working in Entity Framework #2981

Closed
Int32Overflow opened this issue Nov 22, 2023 · 2 comments
Closed

Composite-Type not working in Entity Framework #2981

Int32Overflow opened this issue Nov 22, 2023 · 2 comments

Comments

@Int32Overflow
Copy link

Int32Overflow commented Nov 22, 2023

I have a database which has a composite type called 'tdatespan'.

CREATE TYPE public.tdatespan AS
(
	"Years" int16notnull,
	"Months" int16notnull,
	"Days" int16notnull
);

Unfortunately I can't get this to work in Entity Framework Core (version "Npgsql.EntityFrameworkCore.PostgreSQL" is 8.0.0).

The following error message throws:
System.InvalidOperationException: 'The 'DateSpan' property 'ProductEntity.BestBefore' could not be mapped because the database provider does not support this type. Consider converting the property value to a type supported by the database using a value converter. See https://aka.ms/efcore-docs-value-converters for more information. Alternately, exclude the property from the model using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.'

This is my test setup:

public class TestDbContext : DbContext
{
   public TestDbContext(DbContextOptions options) : base(options)  {   }
   public TestDbContext()  {  }

   protected override void OnModelCreating(ModelBuilder builder)
   {
       base.OnModelCreating(builder);
       builder.Entity<ProductEntity>(b =>
       {
           b.ToTable("\"Products\"", "public");
           b.Property(p => p.Id).IsRequired().ValueGeneratedOnAdd().HasColumnName("\"Id\"");
           b.Property(p => p.BestBefore).IsRequired().HasColumnName("\"BestBefore\"");

           b.HasKey(p => p.Id);
       });
   }
}

public class ProductEntity
{
   public long Id { get; set; }
   public DateSpan BestBefore { get; set; }
}

[Serializable]
public class DateSpan : IEquatable<DateSpan>
{
   public DateSpan(short days, short months, short years)
   {
       Days = days;
       Months = months;
       Years = years;
   }

   public DateSpan()
   {
   }

   public short Days { get; set; }
   public short Months { get; set; }
   public short Years { get; set; }
}

public class DateSpanTranslator : INpgsqlNameTranslator
{
    public string TranslateMemberName(string clrName)
    {
        return clrName;
    }

    public string TranslateTypeName(string clrName)
    {
        return default;
    }
}

internal class Program
{
    static async Task Main(string[] args)
    {
        var dataSourceBuilder = new NpgsqlDataSourceBuilder("<Connection String here>");            
        dataSourceBuilder.MapComposite<DateSpan>("tdatespan", new DateSpanTranslator());

        var service = new ServiceCollection();
        service.AddDbContextPool<TestDbContext>(b => b.UseNpgsql(dataSourceBuilder.Build()));
        var serviceProvider = service.BuildServiceProvider();
        var testDbContext = serviceProvider.GetRequiredService<TestDbContext>();
        var result = await testDbContext.Set<ProductEntity>().ToListAsync();
        Console.WriteLine("Hello, World!");
    }
}

However, if I read directly via DataReader instead of EntityFrameworkCore, it works without any problems:

static async Task Main(string[] args)
{
    var dataSourceBuilder = new NpgsqlDataSourceBuilder("<Connection String here>");            
    dataSourceBuilder.MapComposite<DateSpan>("tdatespan", new DateSpanTranslator());

    await using var dataSource = dataSourceBuilder.Build();
    using (var connection = dataSource.OpenConnection())
    {
      using(var cmd = connection.CreateCommand())
        {
            cmd.CommandText = "SELECT \"BestBefore\" FROM \"Products\" ;";

            using(var reader = cmd.ExecuteReader())
            {
                while (reader.Read())
                {
                    var test = reader.GetFieldValue<DateSpan>(0);
                }
            }
        }
    }
}

Enums are working with EntityFramework and DataReader.

@roji
Copy link
Member

roji commented Nov 24, 2023

Duplicate of #22

@roji roji marked this as a duplicate of #22 Nov 24, 2023
@roji
Copy link
Member

roji commented Nov 24, 2023

Unfortunately, composite types aren't currently supported by the EF provider. This is something I hope to implement (and there's infrastructure development on the EF side that goes in this direction), but it's currently not there.

@roji roji closed this as not planned Won't fix, can't repro, duplicate, stale Nov 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants