If I have either an IPAddress or PhysicalAddress property on an entity and set it up for UseInMemoryDatabase() there will be exceptions when the database is created.
Note that these data types are acceptable in my real database (postgresql)
Thought it may be related to this: https://github.com/aspnet/EntityFrameworkCore/issues/11074
Here is a sample application displaying the problem
``` C#
namespace EfTest
{
public class Program
{
public static void Main(string[] args)
{
using (var db = new MyContext())
{
// Recreate database
db.Database.EnsureDeleted();
db.Database.EnsureCreated();
// Seed database
db.SaveChanges();
}
using (var db = new MyContext())
{
// Run queries
}
Console.WriteLine("Program finished.");
}
}
public class MyContext : DbContext
{
// Declare DBSets
public DbSet<NetworkStuff> NetworkStuffs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// Select 1 provider
optionsBuilder
.UseInMemoryDatabase(databaseName: "modelname");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}
public class NetworkStuff
{
public int Id { get; set; }
public IPAddress IpAddress1 { get; set; }
public PhysicalAddress Mac1 { get; set; }
}
}
```
Exception for IPAddress:
System.InvalidOperationException
HResult=0x80131509
Message=No suitable constructor found for entity type 'IPAddress'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'newAddress' in 'IPAddress(long newAddress)'; cannot bind 'address', 'scopeid' in 'IPAddress(byte[] address, long scopeid)'; cannot bind 'address', 'scopeid' in 'IPAddress(ReadOnlySpanaddress, long scopeid)'; cannot bind 'numbers', 'scopeid' in 'IPAddress(ReadOnlySpan numbers, uint scopeid)'; cannot bind 'numbers', 'scopeid' in 'IPAddress(ushort[] numbers, uint scopeid)'; cannot bind 'address' in 'IPAddress(byte[] address)'; cannot bind 'address' in 'IPAddress(ReadOnlySpan address)'.
Source=Microsoft.EntityFrameworkCore
StackTrace:
at Microsoft.EntityFrameworkCore.Metadata.Conventions.ConstructorBindingConvention.ProcessModelFinalized(IConventionModelBuilder modelBuilder, IConventionContext1 context) at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelFinalized(IConventionModelBuilder modelBuilder) at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelFinalized(IConventionModelBuilder modelBuilder) at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.FinalizeModel() at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel() at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder) at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.<>c__DisplayClass5_0.<GetModel>b__1() at System.Lazy1.ViaFactory(LazyThreadSafetyMode mode)
at System.Lazy1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor) at System.Lazy1.CreateValue()
at System.Lazy1.get_Value() at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder) at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel() at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model() at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__7_3(IServiceProvider p) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies() at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider() at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance() at Microsoft.EntityFrameworkCore.Infrastructure.Internal.InfrastructureExtensions.GetService[TService](IInfrastructure1 accessor)
at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetServiceTService
at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.get_Dependencies()
at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.EnsureDeleted()
at EfTest.Program.Main(String[] args) in C:\Users\name\source\repos\EfTest\EfTest\Program.cs:line 16
Exception for PhysicalAddress (have to comment out IPAddress property)
System.InvalidOperationException
HResult=0x80131509
Message=No suitable constructor found for entity type 'PhysicalAddress'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'address' in 'PhysicalAddress(byte[] address)'.
Source=Microsoft.EntityFrameworkCore
StackTrace:
at Microsoft.EntityFrameworkCore.Metadata.Conventions.ConstructorBindingConvention.ProcessModelFinalized(IConventionModelBuilder modelBuilder, IConventionContext1 context) at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelFinalized(IConventionModelBuilder modelBuilder) at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelFinalized(IConventionModelBuilder modelBuilder) at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.FinalizeModel() at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel() at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder) at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.<>c__DisplayClass5_0.<GetModel>b__1() at System.Lazy1.ViaFactory(LazyThreadSafetyMode mode)
at System.Lazy1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor) at System.Lazy1.CreateValue()
at System.Lazy1.get_Value() at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder) at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel() at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model() at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__7_3(IServiceProvider p) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2.VisitCallSite(ServiceCallSite callSite, TArgument argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies() at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider() at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance() at Microsoft.EntityFrameworkCore.Infrastructure.Internal.InfrastructureExtensions.GetService[TService](IInfrastructure1 accessor)
at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetServiceTService
at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.get_Dependencies()
at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.EnsureDeleted()
at EfTest.Program.Main(String[] args) in C:\Users\Name\source\repos\EfTest\EfTest\Program.cs:line 15
EF Core version: 3.0.0
Database provider: Microsoft.EntityFrameworkCore.InMemory
Target framework: .NET Core 3.0
Operating system: Windows 10
IDE: Visual Studio 2019 16.3.6
@tfadler This is because the in-memory provider doesn't handle these types by default. A workaround is to add value converters when using the in-memory database:
```C#
modelBuilder
.Entity
.Property(e => e.IpAddress1)
.HasConversion(
v => v.ToString(),
v => IPAddress.Parse(v));
modelBuilder
.Entity
.Property(e => e.Mac1)
.HasConversion(
v => v.ToString(),
v => PhysicalAddress.Parse(v));
```
I'm putting this issue on the backlog to make these (or similar) converters built-in so the conversion is done automatically for any provider that doesn't support these types natively.
@ajcvickers Yes that would be a good work around and is for just in memory database.
I was hoping to have an in memory database for some Integration Tests. My boss will likely want to still have those be native type in the actual (postgresql) database. So I can't put the conversions in my OnModelCreating() for my dbcontext.
I guess I could write a new dbcontext class (for ITs) that inherits my current one...so I can have access to the OnModelCreating() to put the conversions in....unless you know of another hook I can get access to modelBuilder with an Integration Test?
@ajcvickers, I'll take this for me!
@tfadler IModelSource can be implemented to decouple OnModelCreating from the DbContext instance.
@tfadler You can add conditional code to OnModelCreating:
C#
if (Database.IsInMemory())
{
modelBuilder
.Entity<NetworkStuff>()
.Property(e => e.Mac1)
.HasConversion(
v => v.ToString(),
v => PhysicalAddress.Parse(v));
}
Re-opening this as I hit issues as soon as I tried to create an example. Specifically, the column is created as nvarchar(max) by default:
CREATE TABLE [Users] (
[Id] int NOT NULL IDENTITY,
[Name] nvarchar(max) COLLATE German_PhoneBook_CI_AS NULL,
[HomeAddress] nvarchar(max) NULL,
CONSTRAINT [PK_Users] PRIMARY KEY ([Id])
);
Also, a query like this:
```C#
context.Users.Where(e => e.HomeAddress == IPAddress.Loopback).ToList();
throws:
Unhandled exception. System.InvalidOperationException: Null TypeMapping in Sql Tree.
at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.SqlTypeMappingVerifyingExpressionVisitor.VisitExtension(Expression extensionExpression)
at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.SqlExpressions.SqlUnaryExpression.VisitChildren(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.VisitExtension(Expression node)
at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.SqlTypeMappingVerifyingExpressionVisitor.VisitExtension(Expression extensionExpression)
at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.SqlExpressions.SqlBinaryExpression.VisitChildren(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.VisitExtension(Expression node)
at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.SqlTypeMappingVerifyingExpressionVisitor.VisitExtension(Expression extensionExpression)
at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.TranslateInternal(Expression expression)
at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.Translate(Expression expression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateExpression(Expression expression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateLambdaExpression(ShapedQueryExpression shapedQueryExpression, LambdaExpression lambdaExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateWhere(ShapedQueryExpression source, LambdaExpression predicate)
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutorTResult
at Microsoft.EntityFrameworkCore.Storage.Database.CompileQueryTResult
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCoreTResult
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_01.<Execute>b__0()
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryTResult
at System.Linq.Enumerable.ToListTSource
at Program.Main() in /home/ajcvickers/AllTogetherNow/Daily/Daily.cs:line 30
```
Split out "Null TypeMapping in Sql Tree" to #21159 - it's a problem specific with the static readonly types on IPAddress. I don't believe it's a fundamental problem with our new IPAddress support - there's an easy workaround, we can probably deal with it separately (and even punt).
Aside from all that, leaving this open until #20917 is merged.
Most helpful comment
@tfadler You can add conditional code to OnModelCreating:
C# if (Database.IsInMemory()) { modelBuilder .Entity<NetworkStuff>() .Property(e => e.Mac1) .HasConversion( v => v.ToString(), v => PhysicalAddress.Parse(v)); }