在使用 EntityFramework 的 C# 项目中使用
Compare
时,我偶然发现了一个有趣的行为。
当使用具有签名
Compare(byte[], byte[])
的方法时,EntityFramework 不使用此方法,而是在 SQL 查询中进行比较。
我的期望是它应该在本地进行评估(并根据配置抛出异常)
public class MyEntity
{
...
[Required]
[ConcurrencyCheck]
public byte[] Timestamp { get; set; }
}
public static int Compare(this byte[] left, byte[] right)
{
throw new InvalidOperationException("...");
}
byte[] someValue = ...;
MyEntity[] items = context.MyEntities
.Where(e => e.Timestamp.Compare(someValue) <= 0)
.ToArray();
此代码不会抛出异常,但会生成如下 SQL 查询:
SELECT .....
FROM [MyEntities] AS [f]
WHERE [f].[Timestamp] <= @__someValue_0
重命名该方法时,该方法不再起作用,并且会引发预期的异常。
在不使用扩展方法的情况下直接使用它时,这也适用。
public static class MyExtensions
{
public static int Compare(byte[] left, byte[] right)
{
throw new InvalidOperationException("...");
}
}
byte[] someValue = ...;
MyEntity[] items = context.MyEntities
.Where(e => MyExtensions.Compare(e.Timestamp, someValue) <= 0)
.ToArray();
造成这种行为的原因是什么?有相关文档吗?
这就是当前 EF Core 提供翻译的方式:
如果您点击此链接,您会发现 EF Core 会转换具有类似签名的任何
Compare
和 CompareTo
方法。
if (method.ReturnType == typeof(int))
{
SqlExpression? left = null;
SqlExpression? right = null;
if (method.Name == nameof(string.Compare)
&& arguments.Count == 2
&& arguments[0].Type == arguments[1].Type)
{
left = arguments[0];
right = arguments[1];
}
else if (method.Name == nameof(string.CompareTo)
&& arguments.Count == 1
&& instance != null
&& instance.Type == arguments[0].Type)
{
left = instance;
right = arguments[0];
}
...