- 3,715,507 Users
- 2,242,778 Discussions
- 7,845,371 Comments
Forum Stats
Discussions
Categories
- 15 Data
- 362.2K Big Data Appliance
- 6 Data Science
- 1.5K Databases
- 461 General Database Discussions
- 3.7K Java and JavaScript in the Database
- 22 Multilingual Engine
- 487 MySQL Community Space
- 3 NoSQL Database
- 7.6K Oracle Database Express Edition (XE)
- 2.8K ORDS, SODA & JSON in the Database
- 416 SQLcl
- 42 SQL Developer Data Modeler
- 184.8K SQL & PL/SQL
- 21K SQL Developer
- 1.8K Development
- 3 Developer Projects
- 32 Programming Languages
- 135.1K Development Tools
- 8 DevOps
- 3K QA/Testing
- 246 Java
- 5 Java Learning Subscription
- 10 Database Connectivity
- 66 Java Community Process
- 1 Java 25
- 9 Java APIs
- 141.1K Java Development Tools
- 6 Java EE (Java Enterprise Edition)
- 153K Java Essentials
- 135 Java 8 Questions
- 86.2K Java Programming
- 270 Java Lambda MOOC
- 65.1K New To Java
- 1.7K Training / Learning / Certification
- 13.8K Java HotSpot Virtual Machine
- 10 Java SE
- 13.8K Java Security
- 3 Java User Groups
- 22 JavaScript - Nashorn
- 18 Programs
- 124 LiveLabs
- 30 Workshops
- 9 Software
- 3 Berkeley DB Family
- 3.5K JHeadstart
- 5.7K Other Languages
- 2.3K Chinese
- 3 Deutsche Oracle Community
- 10 Español
- 1.9K Japanese
- 2 Portuguese
Can you change the Scaffolding mappings in EF Core?
Hi. In ODP.net EF, you can change the default mappings in the configuration before scaffolding. Is this still possible in core?
I ask because NUMBER(2)
to NUMBER(4)
maps to byte, which is unusable with any number over 255. Normally I just map these to short in configuration and the problem goes away, but I'm not sure how to do this in Core as the documentation doesn't mention it except editing the generated classes after the fact.
Thanks.
Best Answer
-
After you scaffold, change the data type to int16 or something similar instead of the default byte. Don't run Scaffold-DbContext again unless you want your customizations overwritten.
Answers
-
Yes, you can use Fluent API to change the default data type mapping.
-
Is there an example of that somewhere? Is that something I can do so that it's generated correctly when I scaffold it via Scaffold-DBScaffold-DbContext? That's the part I'm having an issue with.
Thanks Alex. :)
-
Here's a general tutorial for using Fluent API. The "Column Data Types" section shows how to customize the data type mapping. You just indicate the Oracle DB type you want to map to.
-
I don't see how that solves the problem though? Scaffold-DbContext generated a byte. When I run it again to pick up new database structure changes, it's going to recreate it as a byte.
That's the problem I'm having. A NUMBER(4,0) column comes out as a byte, and as soon as it reads a row with a value like 1234, it fails. I can change the generated classes after the fact, but those changes get wiped out if I run Scaffold-DbContext to recreate from the database again. In the EF6 version, the configuration mapping changes are picked up during this and it would create it as a short instead, which works.
Sorry, but I'm really not understanding what I'd do with the fluent API that would help solve that problem.
-
After you scaffold, change the data type to int16 or something similar instead of the default byte. Don't run Scaffold-DbContext again unless you want your customizations overwritten.
-
Hi Alex. So I tried that, and now saving with the column that has values incompatible with byte gives me the exception below. It doesn't actually matter what's in the column (including null), it simply doesn't work properly. Running it as a byte also isn't an option, because as a NUMBER(4,0), it easily has values that overflow byte.
It's defined in EF as follows:
public short? PlaceCd { get; set; }
modelBuilder.Entity<TempAddress>(entity =>
{
entity.HasIndex(e => e.PlaceCd)
.HasName("XIF5TEMP_ADDRESS");
entity.Property(e => e.PlaceCd).HasColumnName("PLACE_CD");
}
I can't be sure this is the one that's causing the error as the error doesn't specify which column is the problem, but this is the one that overflows if I use the default mappings.
System.Reflection.TargetInvocationException
HResult=0x80131604
Message=Exception has been thrown by the target of an invocation.
Source=System.Private.CoreLib
StackTrace:
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
at Microsoft.EntityFrameworkCore.Update.Internal.KeyValueIndexFactorySource.Create(IKey key)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Microsoft.EntityFrameworkCore.Update.Internal.KeyValueIndexFactorySource.GetKeyValueIndexFactory(IKey key)
at Microsoft.EntityFrameworkCore.Update.Internal.CommandBatchPreparer.AddForeignKeyEdges(Multigraph`2 commandGraph, Dictionary`2 predecessorsMap)
at Microsoft.EntityFrameworkCore.Update.Internal.CommandBatchPreparer.TopologicalSort(IEnumerable`1 commands)
at Microsoft.EntityFrameworkCore.Update.Internal.CommandBatchPreparer.<BatchCommands>d__11.MoveNext()
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable`1 commandBatches, IRelationalConnection connection)
at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChanges(IList`1 entries)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IList`1 entriesToSave)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(DbContext _, Boolean acceptAllChangesOnSuccess)
at Oracle.EntityFrameworkCore.Storage.Internal.OracleExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.DbContext.SaveChanges()
at GNB.ELG.WellVoucher.Website.External.Controllers.VoucherController.Create(VoucherEditVm vm) in C:\workarea\GWIMS\Dev\GNB.ELG.WellVoucher\GNB.ELG.WellVoucher.Website.External\Controllers\VoucherController.cs:line 108
at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()
Inner Exception 1:
InvalidCastException: Unable to cast object of type 'System.Func`3[System.Byte,System.Byte,System.Boolean]' to type 'System.Func`3[System.Int16,System.Int16,System.Boolean]'.
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.SimplePrincipalKeyValueFactory`1.NoNullsCustomEqualityComparer..ctor(ValueComparer comparer)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.SimplePrincipalKeyValueFactory`1..ctor(IProperty property)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.KeyValueFactoryFactory.CreateSimpleFactory[TKey](IKey key)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.KeyValueFactoryFactory.Create[TKey](IKey key)
at Microsoft.EntityFrameworkCore.Metadata.Internal.Key.<>c__19`1.<GetPrincipalKeyValueFactory>b__19_0(Key k)
at Microsoft.EntityFrameworkCore.Internal.NonCapturingLazyInitializer.EnsureInitialized[TParam,TValue](TValue& target, TParam param, Func`2 valueFactory)
at Microsoft.EntityFrameworkCore.Metadata.Internal.Key.GetPrincipalKeyValueFactory[TKey]()
at Microsoft.EntityFrameworkCore.Metadata.Internal.KeyExtensions.GetPrincipalKeyValueFactory[TKey](IKey key)
at Microsoft.EntityFrameworkCore.Update.Internal.KeyValueIndexFactorySource.CreateFactory[TKey](IKey key)
-
So as an update on this, I'm not sure what happened, but I was trying to create an example case of this to demonstrate the problem in a smaller bit of code, and it worked fine.
Then I updated the packages in my project and tried again... and it worked fine.
I'm not sure what changed, but it seems fine now. Thanks Alex.
-
No problem! I was perplexed why you saw an exception. I'm glad to hear it's now working for you.