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

Warn/throw when saving an optional dependent with all null properties when table splitting #24558

Closed
AndriySvyryd opened this issue Mar 31, 2021 · 9 comments
Labels
area-save-changes closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. community-contribution type-enhancement
Milestone

Comments

@AndriySvyryd
Copy link
Member

No description provided.

@umitkavala
Copy link
Contributor

Hi @AndriySvyryd,
I'd like to take this issue.

@AndriySvyryd
Copy link
Member Author

@umitkavala Ok

@AndriySvyryd AndriySvyryd changed the title Warn when saving an optional dependent with all null properties. Warn when saving an optional dependent with all null properties when table splitting Apr 3, 2021
@ajcvickers ajcvickers added this to the 6.0.0 milestone Apr 6, 2021
@umitkavala
Copy link
Contributor

umitkavala commented Apr 9, 2021

public class Order
{
    public int Id { get; set; }
    public OrderStatus? Status { get; set; }
    public DetailedOrder DetailedOrder { get; set; }
}

public class DetailedOrder
{
    public int Id { get; set; }
    public OrderStatus? Status { get; set; }
    public string? BillingAddress { get; set; }
    public string? ShippingAddress { get; set; }
}
modelBuilder.Entity<DetailedOrder>(
    dob =>
    {
        dob.ToTable("Orders");
        dob.Property(o => o.Status).HasColumnName("Status");
    });

modelBuilder.Entity<Order>(
    ob =>
    {
        ob.ToTable("Orders");
        ob.Property(o => o.Status).HasColumnName("Status");
        ob.HasOne(o => o.DetailedOrder).WithOne()
            .HasForeignKey<DetailedOrder>(o => o.Id);
    });


using (var context = new TableSplittingContext())
{
    context.Database.EnsureDeleted();
    context.Database.EnsureCreated();

    context.Add(
        new Order
        {
            Status = OrderStatus.Pending,
        });

    context.SaveChanges();
}

@AndriySvyryd Is this the use case? (From https://docs.microsoft.com/en-us/ef/core/modeling/table-splitting#optional-dependent-entity)
I'm trying to save principal entity without setting optional dependent entity?

@AndriySvyryd
Copy link
Member Author

@umitkavala Not quite.

The use case is more like

using (var context = new TableSplittingContext())
{
    context.Database.EnsureDeleted();
    context.Database.EnsureCreated();

    context.Add(
        new Order
        {
            DetailedOrder = new DetailedOrder()
        });

    context.SaveChanges();
}

Then if you do

using (var context = new TableSplittingContext())
{
    var order = context.Set<Order>().Include(o => o.DetailedOrder).OrderBy(o => o.Id).First();

    // order.DetailedOrder is null even though it wasn't null when saved
}

@umitkavala
Copy link
Contributor

umitkavala commented Apr 17, 2021

@AndriySvyryd I'm just not sure where to check properties values. First I thought it will be at RelationalModelValidator but we need to check during save not model validation.

public virtual InternalEntityEntry PrepareToSave()

Is this the correct place to check null properties? Are we going to throw InvalidOperationException?

@AndriySvyryd
Copy link
Member Author

@umitkavala No, you'd need to do it in

protected virtual IEnumerable<ModificationCommand> CreateModificationCommands(
IList<IUpdateEntry> entries,
IUpdateAdapter updateAdapter,
Func<string> generateParameterName)

That's where we have enough information. Perhaps a helper method in SharedTableEntryMap would be needed to determine whether a given entry is an optional dependent.

Note that this isn't straightforward, so don't feel pressured to submit a PR.

@umitkavala
Copy link
Contributor

umitkavala commented May 6, 2021

When I try to save optional dependent with null properties;

 context.Add(
        new Order
        {
            DetailedOrder = new DetailedOrder()
        });

below warning thrown before code reach CreateModificationCommands

var requiredNonSharedColumnFound = false;
foreach (var property in entityType.GetProperties())
{
if (property.IsPrimaryKey()
|| property.IsNullable)
{
continue;
}
var columnName = property.GetColumnName(table);
if (columnName != null)
{
if (!principalColumns.Contains(columnName))
{
requiredNonSharedColumnFound = true;
break;
}
}
}
if (!requiredNonSharedColumnFound)
{
if (entityType.GetReferencingForeignKeys().Select(e => e.DeclaringEntityType).Any(t => mappedTypes.Contains(t)))
{
throw new InvalidOperationException(
RelationalStrings.OptionalDependentWithDependentWithoutIdentifyingProperty(entityType.DisplayName()));
}
logger.OptionalDependentWithoutIdentifyingPropertyWarning(entityType);
}

@AndriySvyryd AndriySvyryd removed this from the 6.0.0 milestone May 6, 2021
@ajcvickers ajcvickers added this to the 6.0.0 milestone May 7, 2021
@AndriySvyryd
Copy link
Member Author

@umitkavala Yes, that's a warning logged at model validation. We need another warning logged when the user actually tries to insert an optional dependent with all null properties when table splitting. We don't want to throw an exception in this case as there might be working applications doing this.

@umitkavala
Copy link
Contributor

umitkavala commented May 8, 2021

@AndriySvyryd problem is WarningBehavior set to Throw for this message. So it throws an exception and execution stop there. I'll commit my test code as draft for this PR #24856.
image

@AndriySvyryd AndriySvyryd removed their assignment May 31, 2021
@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 May 31, 2021
@AndriySvyryd AndriySvyryd modified the milestones: 6.0.0, 6.0.0-preview6 Jul 2, 2021
@ajcvickers ajcvickers changed the title Warn when saving an optional dependent with all null properties when table splitting Warn/throw when saving an optional dependent with all null properties when table splitting Oct 19, 2021
@ajcvickers ajcvickers modified the milestones: 6.0.0-preview6, 6.0.0 Nov 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-save-changes closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. community-contribution type-enhancement
Projects
None yet
Development

No branches or pull requests

3 participants