Этот код загружает всю мою таблицу в память и фильтрует там.
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)
* отредактировано для включения идентификатора класса и версии 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 в int в linq-to-sql