EntityFramework-Extensions icon indicating copy to clipboard operation
EntityFramework-Extensions copied to clipboard

BulkMerge - Many to Many relationships

Open mr-eric-walter opened this issue 6 years ago • 4 comments

Description

I'm trying to merge a many to many relationship using the graph feature. The Ids are generated out of the database, so I have to key off the Sku for Product and the Name for Manufacturer.

{
  "Products": [
        { 
         "Sku": 111222,
         "Manufacturer": {
            "Name": "Foo", 
             "Description": "Bar"
         }
   ]
}

Table Structure:

Product
   Id
   Sku
ProductMaufacturer
  ProductId
  ManufacturerId
Manufacturer
  Id
  Name
  Description

I'm trying to do something like this:

context.BulkMerge(parentProducts, options =>
{
    options.IncludeGraph = true;
    options.ColumnInputExpression = product => new {
        product.Sku,
    };
    options.ColumnPrimaryKeyExpression = product => new
    {
        product.Sku,
    };
    options.IncludeGraphOperationBuilder = operation =>
    {
        if (operation is BulkOperation<ProductManufacturer> bulkProductManufacturer)
        {
            bulkProductManufacturer.ColumnPrimaryKeyExpression = x => new
            {
                x.Product.Sku,
                x.Manufacturer.Name,
            };
        }
        else if (operation is BulkOperation<Manufacturer> bulkManufacturer)
        {
            bulkManufacturer.ColumnPrimaryKeyExpression = manufacturer => new
            {
                manufacturer.Name,
            };
        }
    };
});

What am I missing? The graph examples don't specify everything outlined in the exception.

Exception

Exception message:
Stack trace:

System.Exception: 'When using `IncludeGraph`, some options must be set in the `IncludeGraphBuilder` (See: https://entityframework-extensions.net/include-graph). The following options must be specified in `IncludeGraphBuilder`: ColumnInputExpression, ColumnPrimaryKeyExpression, IgnoreOnMergeUpdateExpression, LambdaIgnoreOnMergeUpdateExpression, LambdaInputExpression, LambdaPrimaryKeyExpression'

Fiddle or Project (Optional)

If you are able,

Provide a Fiddle that reproduces the issue: https://dotnetfiddle.net/Uqe9sf

Or provide a project/solution that we can run to reproduce the issue.

  • Make sure the project compile
  • Make sure to provide only the code that is required to reproduce the issue, not the whole project
  • You can send private code here: [email protected]

Otherwise, make sure to include as much information as possible to help our team to reproduce the issue.

Note: More information you provide, faster we can implement a solution.

Further technical details

  • EF version: 3.0.0
  • EF Extensions version: 3.0.9
  • Database Provider: Sql Server

mr-eric-walter avatar Oct 13 '19 20:10 mr-eric-walter

Hello @mr-eric-walter ,

The IncludeGraph is not very obvious. Everything that depend on an entity must be specified in the IncludeGraphOperationBuilder.

For example, the BatchSize can be specifed outside but ColumnInputExpression must be specified inside since it depends on an entity type.

So you probably need to do something like this:

context.BulkMerge(parentProducts, options =>
{
    options.IncludeGraph = true;
	options.IncludeGraphOperationBuilder = operation =>
    {
        if (operation is BulkOperation<ProductManufacturer> bulkProductManufacturer)
        {
            bulkProductManufacturer.ColumnPrimaryKeyExpression = x => new
            {
                x.Product.Sku,
                x.Manufacturer.Name,
            };
        }
        else if (operation is BulkOperation<Manufacturer> bulkManufacturer)
        {
            bulkManufacturer.ColumnPrimaryKeyExpression = manufacturer => new
            {
                manufacturer.Name,
            };
        }
        else if (operation is BulkOperation<Product> bulkProduct)
        {
            bulkProduct.ColumnInputExpression = product => new {
                product.Sku,
            };
            bulkProduct.ColumnPrimaryKeyExpression = product => new
            {
                product.Sku,
            };
        }
    };
});

Let me know if you successfully make it work.

Best Regards,

Jonathan

JonathanMagnan avatar Oct 14 '19 16:10 JonathanMagnan

Thank you so much. That helped me get past that issue. Now I'm seeing this issue. Since I do not have IDs for those entities yet, will I not be able to map to the unique value for that entity?

System.InvalidOperationException: 'The property 'ProductId' on entity type 'ProductManufacturer' 
has a temporary value. Either set a permanent value explicitly or ensure that the 
database is configured to generate values for this property.

mr-eric-walter avatar Oct 14 '19 23:10 mr-eric-walter

Hello @mr-eric-walter ,

You will find a working example in the attachment. We used the same entity but with probably some small difference.

On our side, we have found something strange. It looks the ProductId is not returned by default when there is a ColumnInputExpression and ColumnPrimaryKeyExpression set.

So perhaps adding the following line will make your project work:

bulkProduct.ColumnOutputExpression = product => product.ProductID;

We will investigate it on our side why that's happening. But meanwhile, could you try it and let us know if you successfully make it work?

Here is the project we made: EF_ManyToMany.zip

JonathanMagnan avatar Oct 15 '19 11:10 JonathanMagnan

Hello @mr-eric-walter

Since our last conversation, we haven't heard from you.

Did you get the chance to try the example?

Looking forward to hearing from you,

Jon

JonathanMagnan avatar Oct 22 '19 13:10 JonathanMagnan