Duplicate column exception on two different property mappings

Discussion of open issues, suggestions and bugs regarding Entity Framework support in ADO.NET Data providers
Post Reply
HL00
Posts: 7
Joined: Thu 03 Jun 2021 14:08

Duplicate column exception on two different property mappings

Post by HL00 » Tue 15 Jun 2021 09:37

In continuation of viewtopic.php?f=30&t=46693 I have tried another approach of mapping an enum to a string using EF Core and have come across what looks like another devart bug.

If I have an entity with two properties mapped to the same column like this:

Code: Select all

v.Property(x => x.RawValue).HasColumnName("ENUMCOLUMN");
            v.Property(x => x.EnumValue)
              .HasColumnName("ENUMCOLUMN")
              .HasConversion<String>(
                a => FromEnum(a),
                b => ToEnum(b));
                }
And then create a new entity of my type:

Code: Select all

var e = new EnumThing() { EnumValue = TheEnum.Value1 };
            db.enumthings.Add(e);
            db.SaveChanges();
Then I receive the following exception:

Code: Select all

Microsoft.EntityFrameworkCore.DbUpdateException: 'An error occurred while updating the entries. See the inner exception for details.'

Inner Exception
OracleException: ORA-06550: line 4, column 34:
PL/SQL: ORA-00957: duplicate column name
ORA-06550: line 4, column 1:
PL/SQL: SQL Statement ignored

This exception was originally thrown at this call stack:
    Devart.Data.Oracle.dr.a(Devart.Data.Oracle.ay, int)
    Devart.Data.Oracle.dr.a(int, Devart.Data.Oracle.bx)
    Devart.Data.Oracle.OracleCommand.InternalExecute(System.Data.CommandBehavior, System.IDisposable, int, int, bool)
    Devart.Common.DbCommandBase.ExecuteDbDataReader(System.Data.CommandBehavior, bool)
    Devart.Common.DbCommandBase.ExecuteDbDataReader(System.Data.CommandBehavior)
    System.Data.Common.DbCommand.ExecuteReader(System.Data.CommandBehavior)
    Devart.Data.Oracle.Entity.ao.a(System.Data.CommandBehavior)
    Devart.Common.Entity.cw.d(System.Data.CommandBehavior)
    Devart.Data.Oracle.Entity.ao.b(System.Data.CommandBehavior)
    System.Data.Common.DbCommand.ExecuteReader()
Other ways of using this object and this enum mapping do seem to work so it seems like this should be supported. The model builds just fine and I can query on the enum value using LINQ with no issues:

Code: Select all

db.enumthings.Where(x => x.EnumValue == TheEnum.Value1).First();
I am using devart v9.14.1273. Let me know if you'd like a test project again

Shalex
Site Admin
Posts: 9543
Joined: Thu 14 Aug 2008 12:44

Re: Duplicate column exception on two different property mappings

Post by Shalex » Fri 18 Jun 2021 17:13

Mapping two properties to the same column works neither with Devart.Data.Oracle nor with Microsoft.Data.SqlClient. In both cases, the generated SQL is "INSERT INTO TESTTABLEDELETETHIS_2 (ID, ENUMCOLUMN, ENUMCOLUMN) VALUES (:p0, :p1, :p2)" that fails to execute.

HL00
Posts: 7
Joined: Thu 03 Jun 2021 14:08

Re: Duplicate column exception on two different property mappings

Post by HL00 » Wed 23 Jun 2021 12:11

Indeed, but mapping two properties to the same column is supported by EF Core and apparently works for other database+provider combinations (see the response on https://github.com/dotnet/efcore/issues/25062)
I'm guessing you comment implies that this functionality is currently not planned to be supported for devart then?

Shalex
Site Admin
Posts: 9543
Joined: Thu 14 Aug 2008 12:44

Re: Duplicate column exception on two different property mappings

Post by Shalex » Fri 25 Jun 2021 09:04

https://github.com/dotnet/efcore/issues/25062
[...]
I couldn't repro this with SQL Server, so I think it's an issue in the Devart provider.
The problem persists with SQL Server as well:

Code: Select all

using Microsoft.EntityFrameworkCore;
using System;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.Design;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace EnumOracleCrashDemo {
  public class Program {
    //public static string connectionString = @"User Id=scott;Password=tiger;Server=192.168.10.41/orclpdb;Direct=True;license key=...;";
    public static string connectionString = @"Data Source=192.168.10.57\sql2019; User Id=sa; Initial Catalog=test; Application Name=abcd;";

    static void Main(string[] args) {
      //SQL for our table+data:
      //CREATE TABLE TESTTABLEDELETETHIS_2(
      //   ID NUMBER PRIMARY KEY,
      //   ENUMCOLUMN VARCHAR2(50)
      //);

      // var monitor = new Devart.Data.Oracle.OracleMonitor() { IsActive = true, Port = 1000, Host = "127.0.0.1" };

      var db = new TestModel();

      var e = new EnumThing() { ID = 1, EnumValue = TheEnum.Value1 };
      db.enumthings.Add(e);
      db.SaveChanges();
    }
  }

  class TestModel : DbContext {
    public virtual DbSet<EnumThing> enumthings { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder) {
      base.OnModelCreating(modelBuilder);

      var v = modelBuilder.Entity<EnumThing>().ToTable("TESTTABLEDELETETHIS_2");
      v.HasKey(x => x.ID);
      v.Property(x => x.ID).HasColumnName("ID");
      v.Property(x => x.RawValue).HasColumnName("ENUMCOLUMN");
      v.Property(x => x.EnumValue)
        .HasColumnName("ENUMCOLUMN")
        .HasConversion<String>(
          a => FromEnum(a),
          b => ToEnum(b));
    }

    private TheEnum? ToEnum(string b) {
      return typeof(TheEnum).GetEnumValues().Cast<TheEnum>().First(e => e.ToString()[0] == b[0]);
    }

    private string FromEnum(TheEnum? a) {
      return a.ToString().Substring(0, 1);
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
      //optionsBuilder.UseOracle(Program.connectionString);
      optionsBuilder.UseSqlServer(Program.connectionString);

      base.OnConfiguring(optionsBuilder);
    }
  }

  enum TheEnum {
    Value1,
    Value2,
    Value3
  }

  class EnumThing {
    public int ID { get; set; }
    public string RawValue { get; set; }
    [NotMapped]
    public TheEnum? EnumValue { get; set; }
  }
}

Post Reply