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

TPC scenario not supported #28015

Closed
Luigi6821 opened this issue May 12, 2022 · 18 comments
Closed

TPC scenario not supported #28015

Luigi6821 opened this issue May 12, 2022 · 18 comments
Labels
closed-no-further-action The issue is closed and no further action is planned. customer-reported

Comments

@Luigi6821
Copy link

Hi,
Looking at the new build preview I was playing with TPC to check the following scenario:

`public abstract class AMOS_ADDRESS
{
public decimal ADDRESSID { get; set; }

    public string CODE { get; set; }

    public string ALPHACODE { get; set; }
}

public abstract class AMOS_ADDRESSCONTACT
{
    public decimal ADDRESSCONTACTID { get; set; }

    public AMOS_ADDRESS ADDRESS { get; set; }

    public decimal ADDRESSID { get; set; }
}
#endregion

public class ADDRESS : AMOS_ADDRESS
{ }

public class ADDRESSCONTACT : AMOS_ADDRESSCONTACT
{
}

....
modelBuilder.Entity<AMOS_ADDRESS>().ToTable("ADDRESS", "AMOS");
modelBuilder.Entity<AMOS_ADDRESS>().HasKey(e => e.ADDRESSID);
modelBuilder.Entity<AMOS_ADDRESS>().Property(e => e.CODE).HasColumnName("CODE");
modelBuilder.Entity<AMOS_ADDRESS>().Property(e => e.ALPHACODE).HasColumnName("ALPHACODE");
modelBuilder.Entity<AMOS_ADDRESS>().Property(e => e.ADDRESSID).HasColumnName("ADDRESSID");

modelBuilder.Entity<AMOS_ADDRESSCONTACT>().ToTable("ADDRESSCONTACT");
modelBuilder.Entity<AMOS_ADDRESSCONTACT>().HasKey(e => e.ADDRESSCONTACTID);
modelBuilder.Entity<AMOS_ADDRESSCONTACT>().Property(e => e.ADDRESSCONTACTID).HasColumnName("ADDRESSCONTACTID");
modelBuilder.Entity<AMOS_ADDRESSCONTACT>().Property(e => e.ADDRESSID).HasColumnName("ADDRESSID");
modelBuilder.Entity<AMOS_ADDRESSCONTACT>().HasOne(e => e.ADDRESS);`

The error I receive when I try to run

var o = dbContext.Set<ADDRESS>().OrderBy(a => a.ADDRESSID).Take(10);

is:

The corresponding CLR type for entity type 'AMOS_ADDRESS' cannot be instantiated, and there is no derived entity type in the model that corresponds to a concrete CLR type.

The same code is perfectly supported by EF6.
Is the TPC implementation still not yet completed ?

Regards
Luigi

Originally posted by @Luigi6821 in #3170 (comment)

@AndriySvyryd
Copy link
Member

@Luigi6821 Don't call modelBuilder.Entity<AMOS_ADDRESS>().ToTable("ADDRESS", "AMOS"); or modelBuilder.Entity<AMOS_ADDRESSCONTACT>().ToTable("ADDRESSCONTACT");. If the entity type is abstract it means that there should be no rows in the corresponding table. Instead call

modelBuilder.Entity<AMOS_ADDRESS>().UseTpcMappingStrategy();
modelBuilder.Entity<AMOS_ADDRESSCONTACT>().UseTpcMappingStrategy();

modelBuilder.Entity<ADDRESS>().ToTable("ADDRESS", "AMOS");
modelBuilder.Entity<ADDRESSCONTACT>().ToTable("ADDRESSCONTACT");

Also, you can't yet configure a different column name for one of the tables, that's coming in #19811

@AndriySvyryd AndriySvyryd added closed-no-further-action The issue is closed and no further action is planned. customer-reported labels May 13, 2022
@Luigi6821
Copy link
Author

Luigi6821 commented May 16, 2022

Hi @AndriySvyryd
This is my model :

    public abstract class AMOS_ADDRESS 
    {
        public decimal ADDRESSID { get; set; }

        public string CODE { get; set; }

        public string ALPHACODE { get; set; }

        public List<AMOS_ADDRESSCONTACT> CONTACTS { get; set; }
    }

    public abstract class AMOS_ADDRESSCONTACT
    {
        public decimal ADDRESSCONTACTID { get; set; }

        public AMOS_ADDRESS ADDRESS { get; set; }

        public decimal ADDRESSID { get; set; }
    }

    public class ADDRESS : AMOS_ADDRESS
    { }

    public class ADDRESSCONTACT : AMOS_ADDRESSCONTACT
    { }
...

I tried configure it in this way:

modelBuilder.Entity<AMOS_ADDRESS>().UseTpcMappingStrategy();
modelBuilder.Entity<ADDRESS>().ToTable("ADDRESS", "AMOS");
modelBuilder.Entity<ADDRESS>().HasKey(e => e.ADDRESSID);
modelBuilder.Entity<ADDRESS>().Property(e => e.ADDRESSID).HasColumnName("ADDRESSID");
modelBuilder.Entity<ADDRESS>().Property(e => e.CODE).HasColumnName("CODE");
modelBuilder.Entity<ADDRESS>().Property(e => e.ALPHACODE).HasColumnName("ALPHACODE");
modelBuilder.Entity<ADDRESS>().Property(e => e.ADDRESSID).HasColumnName("ADDRESSID");
modelBuilder.Entity<ADDRESS>().HasMany(e => e.CONTACTS);

modelBuilder.Entity<AMOS_ADDRESSCONTACT>().UseTpcMappingStrategy();
modelBuilder.Entity<ADDRESSCONTACT>().ToTable("ADDRESSCONTACT");
modelBuilder.Entity<ADDRESSCONTACT>().HasKey(e => e.ADDRESSCONTACTID);
modelBuilder.Entity<ADDRESSCONTACT>().Property(e => e.ADDRESSCONTACTID).HasColumnName("ADDRESSCONTACTID");
modelBuilder.Entity<ADDRESSCONTACT>().Property(e => e.ADDRESSID).HasColumnName("ADDRESSID");
modelBuilder.Entity<ADDRESSCONTACT>().HasOne(e => e.ADDRESS);

But no luck:
The property 'AMOS_ADDRESS.ADDRESSID' could not be mapped because it is of type 'decimal', which is not a supported primitive type or a valid entity type. ...

Please can you help me on how to configure model builder?
Thanks in advance.

Regards
Luigi

@AndriySvyryd
Copy link
Member

@Luigi6821 What provider are you using? The following configuration might work better:

 modelBuilder.Entity<AMOS_ADDRESS>().UseTpcMappingStrategy();
 modelBuilder.Entity<AMOS_ADDRESS>().HasKey(e => e.ADDRESSID);
 modelBuilder.Entity<AMOS_ADDRESS>().Property(e => e.CODE).HasColumnName("CODE");
 modelBuilder.Entity<AMOS_ADDRESS>().Property(e => e.ALPHACODE).HasColumnName("ALPHACODE");
 modelBuilder.Entity<AMOS_ADDRESS>().Property(e => e.ADDRESSID).HasColumnName("ADDRESSID");
 modelBuilder.Entity<ADDRESS>().ToTable("ADDRESS", "AMOS");

modelBuilder.Entity<AMOS_ADDRESSCONTACT>().UseTpcMappingStrategy();
modelBuilder.Entity<AMOS_ADDRESSCONTACT>().HasKey(e => e.ADDRESSCONTACTID);
modelBuilder.Entity<AMOS_ADDRESSCONTACT>().Property(e => 
    e.ADDRESSCONTACTID).HasColumnName("ADDRESSCONTACTID");
modelBuilder.Entity<AMOS_ADDRESSCONTACT>().Property(e => e.ADDRESSID).HasColumnName("ADDRESSID");
modelBuilder.Entity<AMOS_ADDRESSCONTACT>().HasOne(e => e.ADDRESS);
modelBuilder.Entity<ADDRESSCONTACT>().ToTable("ADDRESSCONTACT");

@Luigi6821
Copy link
Author

Luigi6821 commented May 16, 2022

 modelBuilder.Entity<AMOS_ADDRESS>().UseTpcMappingStrategy();
 modelBuilder.Entity<AMOS_ADDRESS>().HasKey(e => e.ADDRESSID);
 modelBuilder.Entity<AMOS_ADDRESS>().Property(e => e.CODE).HasColumnName("CODE");
 modelBuilder.Entity<AMOS_ADDRESS>().Property(e => e.ALPHACODE).HasColumnName("ALPHACODE");
 modelBuilder.Entity<AMOS_ADDRESS>().Property(e => e.ADDRESSID).HasColumnName("ADDRESSID");
 modelBuilder.Entity<ADDRESS>().ToTable("ADDRESS", "AMOS");

modelBuilder.Entity<AMOS_ADDRESSCONTACT>().UseTpcMappingStrategy();
modelBuilder.Entity<AMOS_ADDRESSCONTACT>().HasKey(e => e.ADDRESSCONTACTID);
modelBuilder.Entity<AMOS_ADDRESSCONTACT>().Property(e => 
    e.ADDRESSCONTACTID).HasColumnName("ADDRESSCONTACTID");
modelBuilder.Entity<AMOS_ADDRESSCONTACT>().Property(e => e.ADDRESSID).HasColumnName("ADDRESSID");
modelBuilder.Entity<AMOS_ADDRESSCONTACT>().HasOne(e => e.ADDRESS);
modelBuilder.Entity<ADDRESSCONTACT>().ToTable("ADDRESSCONTACT");

Hi @AndriySvyryd,
Still same error
[The property 'ADDRESS.ADDRESSID' could not be mapped because it is of type 'decimal', which is not a supported primitive type or a valid entity type. Either explicitly map this property, or ignore it using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in ...]

I'm using SQL Server.

This is the rest of the code:

SqlConnection connection = new SqlConnection()
{
ConnectionString = "User=amos;Password=;Data source=localhost\SQL2019;Initial catalog=ABS10300DEMO"
};

var optionsBuilder = new DbContextOptionsBuilder();
var model = modelBuilder.FinalizeModel();
optionsBuilder.UseModel(model);

connection.Open();

optionsBuilder.UseSqlServer(connection);
using (var dbContext = new DbContext(optionsBuilder.Options))
{
// ===> Here error
var addresses = dbContext.Set

().OrderBy(a => a.ADDRESSID).Take(10);
....

Any suggestions?

Thanks
Luigi

@AndriySvyryd
Copy link
Member

How do you create the ModelBuilder? Why don't you use a derived DbContext instead?

@Luigi6821
Copy link
Author

Luigi6821 commented May 17, 2022

How do you create the ModelBuilder? Why don't you use a derived DbContext instead?

The code I submitted is a simplification of a company software where the model is created using this approach which should be perfectly valid.

Anyway module builder is simple instantiated :

var modelBuilder = new ModelBuilder();

I tried using OnModelCreating and it works.

Please can you give me solution using my approach?
Thanks in advance

Regards
Luigi

@AndriySvyryd
Copy link
Member

Please provide a small self-contained repro project

@Luigi6821
Copy link
Author

Please provide a small self-contained repro project

Here you go.
EFcoreTPC.zip

@AndriySvyryd
Copy link
Member

AndriySvyryd commented May 17, 2022

Targeting SqlServer and using OnModelCreating works:

EFcoreTPC.zip

If you need to call UseModel then use SqlServerConventionSetBuilder.CreateModelBuilder() to create the ModelBuilder

@Luigi6821
Copy link
Author

Luigi6821 commented May 18, 2022

@AndriySvyryd,

I tried using SqlServerConventionSetBuilder... and made some progress but still an error.
I paste here the code I am using:

        var modelBuilder = SqlServerConventionSetBuilder.CreateModelBuilder();//new ModelBuilder();
        modelBuilder.HasDefaultSchema("AMOS");

        modelBuilder.Entity<AMOS_ADDRESS>().UseTpcMappingStrategy();
        modelBuilder.Entity<AMOS_ADDRESS>().HasKey(e => e.ADDRESSID);
        modelBuilder.Entity<AMOS_ADDRESS>().Property(e => e.CODE).HasColumnName("CODE");
        modelBuilder.Entity<AMOS_ADDRESS>().Property(e => e.ALPHACODE).HasColumnName("ALPHACODE");
        modelBuilder.Entity<AMOS_ADDRESS>().Property(e => e.ADDRESSID).HasColumnName("ADDRESSID");
        modelBuilder.Entity<ADDRESS>().HasMany(e => e.CONTACTS);
        modelBuilder.Entity<ADDRESS>().ToTable("ADDRESS", "AMOS");

        modelBuilder.Entity<AMOS_ADDRESSCONTACT>().UseTpcMappingStrategy();
        modelBuilder.Entity<AMOS_ADDRESSCONTACT>().HasKey(e => e.ADDRESSCONTACTID);
        modelBuilder.Entity<AMOS_ADDRESSCONTACT>().Property(e => e.ADDRESSCONTACTID).HasColumnName("ADDRESSCONTACTID");
        modelBuilder.Entity<AMOS_ADDRESSCONTACT>().Property(e => e.ADDRESSID).HasColumnName("ADDRESSID");
        modelBuilder.Entity<AMOS_ADDRESSCONTACT>().HasOne(e => e.ADDRESS);
        modelBuilder.Entity<ADDRESSCONTACT>().ToTable("ADDRESSCONTACT");

        SqlConnection connection = new SqlConnection()
        {
            ConnectionString = "User=amos;Password=<pwd>;Data source=localhost\\SQL2019;Initial catalog=ABS10300DEMO"
        };

        var optionsBuilder = new DbContextOptionsBuilder();
        var model = modelBuilder.FinalizeModel();
        optionsBuilder.UseModel(model);

        connection.Open();

        optionsBuilder.UseSqlServer(connection);
        using (var dbContext = new DerivedDbContext(optionsBuilder.Options))
        {
            var addresses = dbContext.Set<AMOS_ADDRESS>();

=====> Error : System.InvalidOperationException: 'Sequence contains no matching element'
var aAddresses = addresses.ToArray();
=====<
}

Of course AMOS.ADDRESS and AMOS.ADDRESSCONTACT contain rows.
What I am doing wrong?

@AndriySvyryd
Copy link
Member

@Luigi6821 You can debug SQL queries either by profiling in SSMS, calling addresses.ToQueryString() or by examining addresses.DebugView in the debugger

@Luigi6821
Copy link
Author

addresses.ToQueryString()

image

As per attached image the addresses.ToQueryString() raise same error.. Sequence contains no matching element

@AndriySvyryd
Copy link
Member

Please provide the stack trace as well

@Luigi6821
Copy link
Author

Here below stack trace.
=========>
at System.Linq.ThrowHelper.ThrowNoMatchException()
at Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression..ctor(IEntityType entityType, ISqlExpressionFactory sqlExpressionFactory)
at Microsoft.EntityFrameworkCore.Query.SqlExpressionFactory.Select(IEntityType entityType)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.CreateShapedQueryExpression(IEntityType entityType)
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitExtension(Expression extensionExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitExtension(Expression extensionExpression)
at Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlServerQueryableMethodTranslatingExpressionVisitor.VisitExtension(Expression extensionExpression)
at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_01.<Execute>b__0() at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToQueryString(IQueryable source)
at EFCore.TestEFCore.Run() in C:\Users\luigi.esposito\source\repos\ConsoleApp5\EFCore\TestEF.cs:line 46
at ConsoleApp5.Program.Main(String[] args) in C:\Users\luigi.esposito\source\repos\ConsoleApp5\ConsoleApp5\Program.cs:line 11
=============<

@AndriySvyryd AndriySvyryd removed the closed-no-further-action The issue is closed and no further action is planned. label May 18, 2022
@AndriySvyryd
Copy link
Member

@smitpatel

@smitpatel
Copy link
Contributor

TPC is in nightly builds. It is not available in preview4

@AndriySvyryd AndriySvyryd added the closed-no-further-action The issue is closed and no further action is planned. label May 18, 2022
@Luigi6821
Copy link
Author

TPC is in nightly builds. It is not available in preview4

@AndriySvyryd ,
Do I have to wait for preview 5 for this fix?

Regards
Luigi

@AndriySvyryd
Copy link
Member

You can use daily builds

@ajcvickers ajcvickers reopened this Oct 16, 2022
@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Oct 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-no-further-action The issue is closed and no further action is planned. customer-reported
Projects
None yet
Development

No branches or pull requests

4 participants