-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Incorrect value method HasDefaultValue for indexer property #23191
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
Comments
@voronov-maxim I am not able to reproduce this--see my code below. Please attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate. public class BlogContext : DbContext
{
public DbSet<Dictionary<string, object>> Blogs
=> Set<Dictionary<string, object>>("Blog");
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseSqlServer(Your.ConnectionString)
.EnableSensitiveDataLogging()
.LogTo(Console.WriteLine, LogLevel.Information);
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.SharedTypeEntity<Dictionary<string, object>>("Blog", b =>
{
b.Property<int>("Id");
});
}
}
public class Program
{
public static void Main()
{
using (var context = new BlogContext())
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
context.Blogs.Add(new Dictionary<string, object>());
context.SaveChanges();
}
using (var context = new BlogContext())
{
Console.WriteLine(context.Blogs.Single()["Id"]);
}
}
} Output:
|
public class BlogContext : DbContext
{
public DbSet<Dictionary<string, object>> Blogs
=> Set<Dictionary<string, object>>("Blog");
public DbSet<Dictionary<string, object>> Post
=> Set<Dictionary<string, object>>("Post");
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(@"Server=.\sqlexpress;Initial Catalog=Test;Trusted_Connection=Yes;")
.EnableSensitiveDataLogging()
.LogTo(Console.WriteLine, LogLevel.Information);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.SharedTypeEntity<Dictionary<string, object>>("Blog", b =>
{
b.IndexerProperty<int>("Id");
});
modelBuilder.SharedTypeEntity<Dictionary<string, object>>("Post", b =>
{
b.IndexerProperty<int>("Id");
b.IndexerProperty<int>("BlogId");
b.HasOne("Blog", null).WithMany();
});
IMutableEntityType blogEntityType = modelBuilder.Model.FindEntityType("Blog");
//FixHasDefaultValue(blogEntityType.GetProperty("Id"));
}
private static void FixHasDefaultValue(IProperty efProperty)
{
IClrPropertyGetter propertyGetter = efProperty.GetGetter();
FieldInfo hasDefaultValue = propertyGetter.GetType().GetField("_hasDefaultValue", BindingFlags.Instance | BindingFlags.NonPublic)!;
hasDefaultValue.SetValue(propertyGetter, GetDefaultValueFunc(efProperty));
}
private static Delegate GetDefaultValueFunc(IProperty property)
{
ParameterExpression parameterExpression = Expression.Parameter(property.DeclaringEntityType.ClrType);
Expression expression = PropertyBase.CreateMemberAccess(property, parameterExpression, property.PropertyInfo);
expression = Expression.Convert(expression, property.ClrType);
expression = expression.MakeHasDefaultValue(property);
return Expression.Lambda(expression, new[] { parameterExpression }).Compile();
}
}
class Program
{
public static void Main()
{
using (var context = new BlogContext())
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
EntityEntry<Dictionary<string, object>> blog = context.Blogs.Add(new Dictionary<string, object>() { { "Id", -1 } });
blog.Property("Id").IsTemporary = true;
context.Post.Add(new Dictionary<string, object>() { { "BlogId", -1 } });
context.SaveChanges();
}
using (var context = new BlogContext())
{
Console.WriteLine("Id = " + context.Blogs.Single()["Id"] + "; BlogId = " + context.Post.Single()["BlogId"]);
}
}
} Fix bug uncomment //FixHasDefaultValue(blogEntityType.GetProperty("Id")); |
Note for triage: the root cause here is an inconsistency in "default value" checking. The actual value is set to zero (the metadata property type default) when configuring the current value as temporary and then checked against null (the CLR default). |
@ajcvickers Is it related with #23226 ? |
@umitkavala I'm not sure. I haven't investigated #23226 deeply. |
The ClrPropertyGetter.HasDefaultValue method for an indexer property always returns false, although it should return true.
Perhaps this is due to the fact that the property has the wrong type "Object", but must be "Int32", "String", etc.
As a result, when I try to add a new entity to the database with the "DatabaseGeneratedOption.Identity" indexer property I get an exception:
EF Core version: 5.0.0-rtm.20509.3
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 5.0
Operating system: Windows 10 Pro 2004
IDE: Visual Studio 2019 16.8.0 Preview 6.0
The text was updated successfully, but these errors were encountered: