В настоящее время я занимаюсь некоторым рефакторингом кода, который делает мое приложение очень медленным. Я довольно далеко, но мне все еще не хватает некоторых кусочков головоломки, надеюсь, вы можете мне помочь.
Мне нравится повторно использовать некоторый код Linq to SQL внутри моего проекта. Вот мой способ сделать это сейчас:
public DomainAccount GetStandardUserAccount()
{
return this.DomainAccounts.Where(da => da.DomainAccountType == DomainAccountType.Standarduser).First() as DomainAccount;
}
var CurrentSituation = _context.Employees.ToList().Where(e => e.GetStandardUserAccount().Username.Contains("test")).ToList();
Небольшое уточнение: у каждого сотрудника есть несколько учетных записей домена, одна из которых всегда является стандартной (DomainAccountType) domainaccount.
Поскольку Linq не может преобразовать метод C# в sqlstatement (даже если его код linq to sql только), мне нужно сначала преобразовать dbset в список, чтобы я мог использовать GetStandardUserAccount (). Этот код работает медленно из-за всего преобразования dbset. Есть ли способ повторно использовать linq для кода sql, не превращая его в метод? Я прочитал несколько тем, и вот что я получил до сих пор:
Func<Employee, DomainAccount> GetStandardDomainAccount = x => x.DomainAccounts.FirstOrDefault(d => d.DomainAccountType == DomainAccountType.Standarduser);
var TheGoal = _context.Employees.Where(e => e.GetStandardDomainAccount().Username.Contains("Something")).ToList();
1) Если эти лямбды переводятся в SQL (предположим, что это из-за переменной _context), то, по крайней мере, у вас есть проблема с запросом: string.Contains приводит к LIKE '%whatever%', который, в свою очередь, не использует индексы. 2) as без проверки на нуль - это путь к NRE. Если что-то должно бытьDomainAccount, то приведите это явно. Если это возможноDomainAccount, и это нормально, когда это не являетсяDomainAccount, то используйте as с последующей проверкой нуля.
1) linq будет переведен в sql, но string.contains всегда работает для меня (см. Текущее решение). 2) Я не уверен, что мне делать с этим отзывом. В методе C# используется 'as', но следует ли мне использовать его и в моем func <>?
@Pieter Я удалил свой ответ, так как он бесполезен для Linq2Entities.





Ответ на этот вопрос немного сложнее, чем кажется. Чтобы позволить linq выполнять код C#, вам нужно сделать функцию выражением, чтобы входные и выходные данные интерпретировались не как код, а как какое-то значение. Решение выглядит так:
private Expression<Func<TPeople, bool>> GetDefaultDomainAccount<TPeople>(Func<DomainAccount, bool> f) where TPeople : Person
{
return (a) => f(a.DomainAccounts.FirstOrDefault(d => d.DomainAccountType == DomainAccountType.Standarduser));
}
Теперь код можно вызвать следующим образом:
public IQueryable<TPeople> GetPeopleByUsername<TPeople>(string username) where TPeople : Person
{
GetPeople<TPeople>().Where(GetDefaultDomainAccount<TPeople>(d => d.Username == username));
return people;
}
вместо этого:
public IQueryable<TPeople> GetPeopleByUsername<TPeople>(string username) where TPeople : Person
{
username = username.ToUpper();
var people = GetPeople<TPeople>()
.Where(a => a.DomainAccounts.FirstOrDefault(d => d.DomainAccountType == DomainAccountType.Standarduser).Username.ToUpper().Contains(username));
return people;
}
Это полезно
Сначала вам понадобится
Func, а неExpression<Func>. В любом случае вы должны передать это вызов, либо позвонивInvoke, либо просто().