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

Allow database default values for FK properties that are part of a composite key #29047

Merged
merged 2 commits into from
Sep 12, 2022

Conversation

ajcvickers
Copy link
Member

Fixes #27299

@ajcvickers ajcvickers requested a review from a team September 10, 2022 23:26
@@ -708,7 +708,7 @@ static bool IsNotNullAndFalse(object? value)
{
foreach (var key in entityType.GetDeclaredKeys())
{
foreach (var property in key.Properties)
foreach (var property in key.Properties.Where(p => !p.IsForeignKey()))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it make sense to also stop warning on composite PKs that don't contain an FK?

@localhost09
Copy link

Coming back to this issue #27299 which was fixed with this merge.
It appears to work for the top level entities, but not for child entities.
Adding to the context works, saving results in exception.

Setup:

  • BaseModel which all models are inheriting from. Is used primarily for row isolation between tenants.
  • Besides the FK, child entity B has a PK (composite Key to ensure uniqueness within a tenant)
  • The TenantId is injected using a Valuegenerator (which is called when adding to context as expected)

BaseModel:

public abstract class BaseModel
{
        public virtual Tenant Tenant { get; set; }
        public virtual string TenantId { get; set; }
}

//Inherited Entity A

public class A : BaseModel
{
        [Key]
        [MaxLength(36)]
        public string SomeKeyField {get; set; }
        public string Name { get; set; }
        public virtual ICollection<B> ChildListOfB { get; set; }
}

//Child Entity B

public class B : BaseModel
{
        public string SomeExtId { get; set; }
        public string SomeOtherValue { get; set; }
}

//Tenant Entity 
 public class Tenant 
{
        [Key]
        [MaxLength(36)]
        public string TenantId {get; set; }
     
}

// OnModelCreating showing for B for now - same for all entities 

modelBuilder.Entity<B>().HasKey(pi => new { pi.TenantId, pi.SomeExtId, pi.SomeOtherValue });
modelBuilder.Entity<B>().Property(e => e.TenantId).HasValueGenerator<VG>();

//Value Generator (VG) 

    public class VG: ValueGenerator<string>
    {

       public override bool GeneratesTemporaryValues => false;

        public override string? Next(EntityEntry entry)
        {

            var s = (entry.Context as OwnDbContext);
            if (s != null)
                return s.SomeProp.GetTenantId();
            return null;
        }
    }

Exception:

The value of 'B.TenantId' is unknown when attempting to save changes. This is because the property is also part of a foreign key for which the principal entity in the relationship is not known.'

Current workaround:
Overriding SaveChangesAsync and adding the value explicitly

entityEntry.CurrentValues["TenantId"] = _internalField.GetTenantId();

Versions
Microsoft.EntityFrameworkCore 7.0.0
Target Framework: net6

@ajcvickers
Copy link
Member Author

@localhost09 Please open a new issue and attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

How to correctly configure a composite primary key with HasDefault() for Sqlite?
3 participants