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

Re-building relationships can cause annotations to be lost #7674

Closed
ajcvickers opened this issue Feb 22, 2017 · 3 comments
Closed

Re-building relationships can cause annotations to be lost #7674

ajcvickers opened this issue Feb 22, 2017 · 3 comments
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Milestone

Comments

@ajcvickers
Copy link
Member

In the code below a shadow FK property is specified when initially building the relationship. An annotation is then put on one of the navigations. The FK is then re-defined to be nullable. This results in the annotation no longer being present on the navigation, presumably because annotations were not copied when the relationship was re-built.

public class Context : DbContext
{
    public DbSet<Buyer> Buyers { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Buyer>()
            .HasMany(b => b.PaymentMethods)
            .WithOne()
            .HasForeignKey("BuyerId")
            .OnDelete(DeleteBehavior.Cascade);

        modelBuilder.Entity<Buyer>()
            .Metadata
            .FindNavigation(nameof(Buyer.PaymentMethods))
            .SetPropertyAccessMode(PropertyAccessMode.Field);

        modelBuilder.Entity<PaymentMethod>()
            .Property<int>("BuyerId").IsRequired();

        // Fails
        Debug.Assert(modelBuilder.Entity<Buyer>()
                         .Metadata
                         .FindNavigation(nameof(Buyer.PaymentMethods))
                         .GetPropertyAccessMode() == PropertyAccessMode.Field);
    }
}

public class Buyer
{
    public int Id { get; set; }

    public ICollection<PaymentMethod> PaymentMethods { get; set; }
}

public class PaymentMethod
{
    public int Id { get; set; }
}

Model before FK is made non-nullable:

Model: 
  EntityType: Buyer
    Properties: 
      Id (int) Required PK ReadOnlyAfterSave RequiresValueGenerator ValueGenerated.OnAdd 0 0 0 -1 0
    Navigations: 
      PaymentMethods (<PaymentMethods>k__BackingField, ICollection<PaymentMethod>) Collection ToDependent PaymentMethod PropertyAccessMode.Field 0 -1 1 -1 -1
        Annotations: 
          PropertyAccessMode: Field
    Keys: 
      Id PK
    Annotations: 
      Relational:TableName: Buyers
      RelationshipDiscoveryConvention:NavigationCandidates: System.Collections.Immutable.ImmutableSortedDictionary`2[System.Reflection.PropertyInfo,System.Type]
  EntityType: PaymentMethod
    Properties: 
      Id (int) Required PK ReadOnlyAfterSave RequiresValueGenerator ValueGenerated.OnAdd 0 0 0 -1 0
      BuyerId (no field, Nullable<int>) Shadow FK Index 1 1 1 0 1
    Keys: 
      Id PK
    Foreign keys: 
      BuyerId -> Buyer.Id ToDependent: PaymentMethods
    Annotations: 
      RelationshipDiscoveryConvention:NavigationCandidates: System.Collections.Immutable.ImmutableSortedDictionary`2[System.Reflection.PropertyInfo,System.Type]
Annotations: 
  ProductVersion: 1.1.0-rtm-22752
  SqlServer:ValueGenerationStrategy: IdentityColumn

Model after FK is made nullable:

Model: 
  EntityType: Buyer
    Properties: 
      Id (int) Required PK ReadOnlyAfterSave RequiresValueGenerator ValueGenerated.OnAdd 0 0 0 -1 0
    Navigations: 
      PaymentMethods (<PaymentMethods>k__BackingField, ICollection<PaymentMethod>) Collection ToDependent PaymentMethod 0 -1 1 -1 -1
    Keys: 
      Id PK
    Annotations: 
      Relational:TableName: Buyers
      RelationshipDiscoveryConvention:NavigationCandidates: System.Collections.Immutable.ImmutableSortedDictionary`2[System.Reflection.PropertyInfo,System.Type]
  EntityType: PaymentMethod
    Properties: 
      Id (int) Required PK ReadOnlyAfterSave RequiresValueGenerator ValueGenerated.OnAdd 0 0 0 -1 0
      BuyerId (no field, int) Shadow Required FK Index 1 1 1 0 1
    Keys: 
      Id PK
    Foreign keys: 
      BuyerId -> Buyer.Id ToDependent: PaymentMethods
    Annotations: 
      RelationshipDiscoveryConvention:NavigationCandidates: System.Collections.Immutable.ImmutableSortedDictionary`2[System.Reflection.PropertyInfo,System.Type]
Annotations: 
  ProductVersion: 1.1.0-rtm-22752
  SqlServer:ValueGenerationStrategy: IdentityColumn
@AndriySvyryd
Copy link
Member

Related to #1923

@andrelmp
Copy link

had the same issue, it took almost a day trying to figure out why SetPropertyAccessMode doesn't work.
Thanks @ajcvickers saved my day

@ajcvickers ajcvickers modified the milestones: 2.0.0-preview1, 2.0.0 Apr 19, 2017
@TsengSR
Copy link

TsengSR commented Apr 27, 2017

Thanks @ajcvickers! This one bite me too and I spent 4 days trying to hunt it down, until I finally realized that the .SetField call is being ignored and EF Core always used the Navigation property!

Pushing the .SetField and SetPropertyAccessMode after the relationships worked as a workaround.

@AndriySvyryd AndriySvyryd added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Jun 3, 2017
@AndriySvyryd AndriySvyryd removed their assignment Jun 3, 2017
pmiddleton pushed a commit to pmiddleton/EntityFramework that referenced this issue Jun 8, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Projects
None yet
Development

No branches or pull requests

5 participants