linq2db.EntityFrameworkCore
linq2db.EntityFrameworkCore copied to clipboard
Merge doesn't include fields from the output expression
I have a situation like this:
- The main entity
Awhich is stored in the Db and is registered with EF Core. The column names here are UPPER_SNAKE_CASE. - The model I use for updates, which includes a subset of fields. (Call it
AModel). This gets the default field names. This data is stored in a temp table with which the merge happens. - An env context, which fills in the default values that are required in
Abut missing inAModel(but not the id). - An company owner filter applied to
Abefore doing the merge, which just leavesAwhere the company id is some fixed value, if that's relevant.
In the merge query, I do an insert of A with values from AModel as well as the additional context values, setting the missing fields to their default values if needed; I also do an update of A for the fields that are present on AModel.
I want to output the result in a temp table as Code, Id pairs (both being present on A, but only Code being present on AModel). It complains to me that ID was not found in the query.
var mappingsTable = await linq2dbContext.CreateTempTableAsync<CodeToIdMapping>(
tableName: cache.TempTableName,
cancellationToken: cancellationToken);
Dictionary<string, int> codeToIdMap;
try
{
await using var tempTable = await linq2dbContext.CreateTempTableAsync(
values,
cancellationToken: cancellationToken);
var insertExpression = cache.GetInsertExpression(contextConstant);
var q = _dbContext.Set<TEntity>()
.Where(ownerHelper)
.AsCte()
.Merge()
.Using(tempTable)
.On(cache.ComparisonExpression)
.UpdateWhenMatched(cache.UpdateExpression)
.InsertWhenNotMatched(insertExpression);
if (shouldDelete)
q = q.DeleteWhenNotMatchedBySource();
await q.MergeWithOutputIntoAsync(
mappingsTable,
cache.CreateMappingExpression,
cancellationToken);
codeToIdMap = await AsyncExtensions.ToDictionaryAsync(
mappingsTable,
x => x.Code,
x => x.Id,
cancellationToken);
}
catch (Exception)
{
await mappingsTable.DisposeAsync();
throw;
}
For the CreateMappingExpression, I'm using the 3 parameter overload. It's created in a generic function that knows TEntity has a Code and an Id, but I expect working with generics through interfaces to be allowed by the library:
Expression<Func<string, TEntity, TEntity, CodeToIdMapping>> createMappingExpression =
(_, _, c) => new()
{
Code = c.Code,
Id = c.Id,
};
Is it not allowed to output the ids of newly created objects in the output clause? I figure I should just do another query if that's not allowed.
The error I'm seeing is:
(0x80131904): Invalid column name 'ID'.
Database name 'tempdb' ignored, referencing object in tempdb.
Database name 'tempdb' ignored, referencing object in tempdb.
The logging had to be enabled prior to creating the context, I assume. It did include the ID column:
OUTPUT
[INSERTED].[CODE],
[INSERTED].[ID]
INTO [tempdb]..[#tempTable]
(
[Code],
[Id]
)
But it still produces the error about missing the ID column.
Note that ID is an autoincremented column (identity + primary key in sql server).