【发布时间】:2019-09-27 05:30:22
【问题描述】:
这段代码将我的整个表格下载到内存中并在那里过滤。
class Book
{
Id<Book> BookId;
Id<Author> AuthorId;
}
class Person
{
Id<Person> PersonId;
}
class BookLookup
{
List<Book> GetBooksForPerson(DbContext db, Id<Person> personId)
{
// yes authorId maps 1-to-1 to personId, legacy
// codebase, can't change that right now
return db.Books
.Where(b => (int)b.AuthorId == (int)personId)
.ToList();
}
}
此代码在 SQL 中运行,仅下载过滤后的行。
class BookLookup
{
List<Book> GetBooksForPerson(DbContext db, Id<Person> personId)
{
// yes authorId maps 1-to-1 to personId, legacy
// codebase, can't change that right now
var authorId = (Id<Author>)(int)personId;
return db.Books
.Where(b => b.AuthorId == authorId)
.ToList();
}
}
两种解决方案都可以编译和工作,但一种会导致巨大的性能问题。
除了非常小心之外,如何防止 LINQ 下载我的整个表?
我想要这样的东西,当它无法转换为 sql 时,它会抛出或编译失败。
db.Books.WhereDb(b => (int)b.AuthorId == (int)personId)
db.Books.Where(b => (int)b.AuthorId == (int)personId,
FilterOption.MustRunInDb)
已编辑以包含 id 类和 EF 版本:
public struct Id<T> : IEquatable<Id<T>>, IComparable
{
private readonly int _value;
private Id(int value)
{
_value = value;
}
public static explicit operator int(Id<T> instance)
{
return instance._value;
}
public static explicit operator Id<T>(int value)
{
return new Id<T>(value);
}
public static bool operator ==(Id<T> value1, Id<T> value2)
{
return value1.Equals(value2);
}
public static bool operator !=(Id<T> value1, Id<T> value2)
{
return !(value1 == value2);
}
public bool Equals(Id<T> other)
{
return _value.Equals(other._value);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
return obj is Id<T> type && Equals(type);
}
public override int GetHashCode()
{
return _value.GetHashCode();
}
/// <summary>
/// Prints the debug string representation of this object
/// </summary>
/// <returns></returns>
public override string ToString()
{
var typeName = GetType().GenericTypeArguments.First().Name;
return $"Id<{typeName}>:{_value}";
}
public int CompareTo(Id<T> obj)
{
return _value.CompareTo(obj._value);
}
public int CompareTo(object obj)
{
if (ReferenceEquals(null, obj)) return 1;
if(obj is Id<T> type)
{
return CompareTo(type);
}
return 1;
}
}
使用 EF Core (v2.1.4) 和自定义助手将 Id<T> 转换为 linq-to-sql 中的 int
【问题讨论】:
-
我碰巧方便地在
DbContext中进行的快速测试,在您的两种模式之间生成的查询没有明显差异。对我来说,它们都在数据库上完全运行。您能否展示您如何在Id<T>中实现int演员表?这可能会对事情的执行方式产生一些影响。 -
这是 EF6 还是 EF Core?
-
我的测试是在 EF6 中完成的。正如 David 的评论所暗示的那样,Core 也可能会改变一些事情。
-
@BradleyUffner 实际上,我怀疑 EF6 实际上会抛出错误,而不是拖入 RAM 中执行类似的代码,而 EFCore 会秘密地在内存中执行操作,除非您告诉它不要这样做。
-
我完全预计会收到有关不支持表达式的错误。我很惊讶得到我所做的结果。
标签: c# performance linq entity-framework-core