artiomchi / FlexLabs.Upsert

FlexLabs.Upsert is a library that brings UPSERT functionality to common database providers for Entity Framework in their respective native SQL syntax
MIT License
516 stars 81 forks source link

Upsert Class with IEnumerable Property #142

Closed Stolzenberg closed 1 year ago

Stolzenberg commented 1 year ago

Hello,

In my generic example here, I only want to add animals to a stable, but never remove any and I want to do this without a get call before.

Clearly as it is currently implemented, it overwrites the existing animals always, but even so it crashes in the reflection and does not find my collection of animals.

public class Stable
{
    public Guid Id { get; set; }
    public IEnumerable<Animal> Animals { get; set; }
}

public class Animal
{
    public Guid Id { get; set; }
    public string Name { get; set; }
}
public async Task Upsert(Stable stable)
{
     await dbContext.Stables.Upsert(stable)
         .On(dbStable=> dbStable.Id)
            .WhenMatched((dbStable, incomingStable) => new Stable()
            {
                Id = dbStable.Id,
                Animals = incomingStable.Animals,
            })
            .RunAsync();
]

Error:

System.InvalidOperationException
Unknown property Animals
   at FlexLabs.EntityFrameworkCore.Upsert.Runners.RelationalUpsertCommandRunner.PrepareCommand[TEntity](IEntityType entityType, ICollection`1 entities, Expression`1 match, Expression`1 updater, Expression`1 updateCondition, RunnerQueryOptions queryOptions)+MoveNext() in /_/src/FlexLabs.EntityFrameworkCore.Upsert/Runners/RelationalUpsertCommandRunner.cs:line 124
   at FlexLabs.EntityFrameworkCore.Upsert.Runners.RelationalUpsertCommandRunner.RunAsync[TEntity](DbContext dbContext, IEntityType entityType, ICollection`1 entities, Expression`1 matchExpression, Expression`1 updateExpression, Expression`1 updateCondition, RunnerQueryOptions queryOptions, CancellationToken cancellationToken) in /_/src/FlexLabs.EntityFrameworkCore.Upsert/Runners/RelationalUpsertCommandRunner.cs:line 398
vamsidogiparthi commented 1 year ago

I just started using this Upsert operation and doing a POC. So, I might be wrong but in SQL you cannot have a IEnumerable as a direct column. You usually achieve this using FK and with one to many or many to many relationship, with navigation properties in the respective classes. As we know navigation properties usually are to get related objects. We cannot directly update or create them via upsert operation. As It internally uses Merge statement which works on a single target class per clause and doesn't recognize these virtual tables (navigation properties).

so, u might want to add an extension method or override of whenonmatched method to ur need.