EntityFramework-Plus: "Invalid column name 'Id'." at UpdateFromQuery when using Where-condition with related entity
1. Description
I am trying to run the following query:
var deletedItems = db.OrderItems.Where(i => !i.IsDeleted && !i.Order.IsCompleted && i.Order.OrderDate < margin)
.UpdateFromQuery(i => new OrderItem()
{
IsDeleted = true,
DeletedReason = DeletedReason.Cleanup,
DeletedDate = deletionDate,
TransactionId = transactionId,
});
On the following models (simplified):
public class OrderItem
{
[Key]
public int Id { get; set; }
[ForeignKey(nameof(Order)), Column("Order_Id")]
public int OrderId { get; set; }
public virtual Order Order { get; set; }
public bool IsDeleted { get; set; }
public DeletedReason? DeletedReason { get; set; }
public DateTime? DeletedDate { get; set; }
public Guid? TransactionId { get; set; } = Guid.NewGuid();
}
public class Order
{
[Key]
public int Id { get; set; }
public DateTime OrderDate { get; set; }
public bool IsCompleted { get; set; }
public virtual List<OrderItem> Items { get; set; } = new ();
}
2. Exception
This results in the following exception:
System.Data.SqlClient.SqlException (0x80131904): Invalid column name 'Id'.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.NonQuery(DbCommand command, DbCommandInterceptionContext interceptionContext)
at .[](IQueryable`1 , Expression`1 )
at DbContextExtensions.[](IQueryable`1 , Expression`1 , Action`1 , Boolean )
at DbContextExtensions.UpdateFromQuery[TEntity](IQueryable`1 query, Expression`1 updateExpression, Action`1 bulkOperationFactory)
If I log the generated SQL it really is invalid. Here the main parts of it (there is a lot of more SQL in the middle, as OrderItem
has many inherited types):
UPDATE A
SET A.[IsDeleted] = @zzz_BatchUpdate_0,
A.[DeletedReason] = @zzz_BatchUpdate_1,
A.[DeletedDate] = @zzz_BatchUpdate_2,
A.[TransactionId] = @zzz_BatchUpdate_3
FROM [dbo].[EventTicket@OrderItems] AS A
INNER JOIN ( SELECT
1 AS [C1],
[Project13].[C1] AS [C2],
-- ...
[Project13].[C30] AS [C30]
FROM (
-- ....
) AS [Project13]
OUTER APPLY (SELECT [Project14].[C2] AS [C2], [Project14].[C3] AS [C3]
FROM ( SELECT
[Extent7].[Id] AS [C1],
[Extent7].[OrderDate] AS [C2],
[Extent7].[IsCompleted] AS [C3]
FROM [dbo].[EventTicket@Orders] AS [Extent7]
) AS [Project14]
WHERE [Project13].[C29] = [Project14].[C1] ) AS [Filter1]
WHERE ([Project13].[C4] <> 1) AND ([Filter1].[C3] <> 1) AND ([Filter1].[C2] < @p__linq__0)
) AS B ON A.[Id] = B.[Id]
The error is from the very last ON A.[Id] = B.[Id]
- there is no [Id] on B and I also think it should be A.[Order_Id]?
3. Fiddle or Project
https://dotnetfiddle.net/6N3nfr - BUT this example works, I’m trying to find out why or what’s the difference to my real code…
4. Any further technical details
I’m using the latest version of EF 6 and EF-Plus/-Extensions as of today (2021-10-30).
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 16 (5 by maintainers)
Please find attached a minimal reproduction example. Bug-related comments are annotated with
FIXME
. BugEFExtMinRepro.zipEffectively, this bug seems triggered by a very large number of columns in the base class table, in a TPT setup. (the repro mimicks the large legacy application that triggered the bug).
Furthermore, depending on the number of child classes in the TPT hierarchy, it seems I can trigger either an “Invalid column name ‘ID’” or a “Sequence contains no elements” error, but I haven’t explored the latter.