Closed bryfa closed 1 year ago
@bryfa I've run your code and I do get the following exception when fifth and sixth cases. Is this what you are reporting as the issue, or is it something else about the behavior here?
Unhandled exception. System.InvalidOperationException: No backing field could be found for property 'BarId' of entity type 'Owned' and the property does not have a getter.
at Microsoft.EntityFrameworkCore.PropertyBaseExtensions.GetMemberInfo(IPropertyBase propertyBase, Boolean forMaterialization, Boolean forSet)
at Microsoft.EntityFrameworkCore.Metadata.Internal.ClrPropertyGetterFactory.Create(IPropertyBase property)
at Microsoft.EntityFrameworkCore.Metadata.Internal.PropertyBase.<>c.<get_Getter>b__33_0(PropertyBase p)
at Microsoft.EntityFrameworkCore.Internal.NonCapturingLazyInitializer.EnsureInitialized[TParam,TValue](TValue& target, TParam param, Func`2 valueFactory)
at Microsoft.EntityFrameworkCore.Metadata.Internal.PropertyBase.get_Getter()
at Microsoft.EntityFrameworkCore.PropertyBaseExtensions.GetGetter(IPropertyBase propertyBase)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityEqualityRewritingExpressionVisitor.CreatePropertyAccessExpression(Expression target, IProperty property)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityEqualityRewritingExpressionVisitor.CreateKeyAccessExpression(Expression target, IReadOnlyList`1 properties)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityEqualityRewritingExpressionVisitor.RewriteEntityEquality(Boolean equality, IEntityType entityType, Expression left, INavigation leftNavigation, Expression right, INavigation rightNavigation, Boolean subqueryTraversed)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityEqualityRewritingExpressionVisitor.RewriteEquality(Boolean equality, Expression left, Expression right)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityEqualityRewritingExpressionVisitor.VisitBinary(BinaryExpression binaryExpression)
at System.Linq.Expressions.BinaryExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityEqualityRewritingExpressionVisitor.RewriteAndVisitLambda(LambdaExpression lambda, EntityReferenceExpression source)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityEqualityRewritingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityEqualityRewritingExpressionVisitor.VisitSelectMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityEqualityRewritingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityEqualityRewritingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityEqualityRewritingExpressionVisitor.Rewrite(Expression expression)
at Microsoft.EntityFrameworkCore.Query.QueryTranslationPreprocessor.Process(Expression query)
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_0`1.<Execute>b__0()
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
at System.Linq.Queryable.Single[TSource](IQueryable`1 source)
at EfBug.Program.Main(String[] args) in C:\Stuff\MyRepros\AllTogetherNow\ThreeOne\ThreeOne.cs:line 210
Yes that's the main issue here. But there is more going on.. In the previous version it was allowed to leave out the real property on the owned class:
public string Value => _value; // <-- was not needed in previous versions
with this mapping:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Bar>().OwnsOne(e => e.Owned, p =>
{
p.Property<string>("Value").HasColumnName("Owned"); //.IsRequired();
});
}
In the previous version(EF Core 2.2) it worked perfectly without the property, because "Value" was a "shadow property" on the entity. In this version its required.
--edit I have read the breaking changes list and noticed that this was reported. So now we need to do this:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Bar>().OwnsOne(e => e.Owned, p =>
{
p.Property("_value").HasColumnName("Owned");
});
}
and then we can remove the Value property from the owned type.
Another strange behavior I came across is the "IsRequired()" setting on this property. When set and after update the database does not have the "NOT NULL" constraint on the "Value object" column. Will check this again.
Another strange behavior I came across is the "IsRequired()" setting on this property. When set and after update the database does not have the "NOT NULL" constraint on the "Value object" column.
This is likely a consequence of the change to to optional owned entities. See https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-3.0/breaking-changes#de and https://github.com/dotnet/efcore/issues/18299#issuecomment-587152089
In the previous version(EF Core 2.2) it worked perfectly without the property, because "Value" was a "shadow property" on the entity.
This probably doesn't matter much, but if the _value
field existed and was being used, then this wasn't technically a shadow property, but rather a property mapped directly to the field. Shadow properties don't have any storage (i.e. no explicit or generated field) for the value in the entity instance itself. Hopefully it's a bit clearer in the 3.1 version that the _value
field is explicitly mapped.
I've got the same problem as mentioned here https://github.com/dotnet/efcore/issues/20073#issuecomment-592052242. So, what exactly is solution to this issue?
Writing and retrieving ValueObjects not working properly
Steps to reproduce
The sample fails on the 5th and 6th selection. Also note that when the Value property is removed in the Owned type class. We get different results.
Further technical details
EF Core version: 3.1.2 Database provider: Microsoft.EntityFrameworkCore.SqlServer Target framework: .NET Core 3.1 Operating system: Windows10 IDE: Visual Studio 2019 16.3