Определите запрос LAMBDA в свойстве, чтобы его можно было повторно использовать - PullRequest
0 голосов
/ 09 июня 2018

Я пытаюсь определить лямбда-запрос в свойстве первой модели EF моего кода, как показано ниже, как GetLatestTransaction:

public class ApplicationUser : IdentityUser
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public virtual List<TransactionModel> Transactions { get; set; }

    public TransactionModel GetLatestTransaction { 
        get {
            return Transactions.OrderByDescending(x => x.Created).FirstOrDefault();
        }
    }
}

Причина в том, что я не хочучтобы повторно вводить этот запрос во многих местах и ​​иметь его в одном месте, уменьшить вероятность ошибки.

Я хочу использовать это в запросе, подобном этому:

var user = _DB.Users
.Select(u => new UserDetailsView()
{
    Id = u.Id,
    FirstName= u.FirstName,
    LastName= u.LastName,
    Balance = u.GetLatestTransaction.ValueResult
}).FirstOrDefault(x => x.Id == userId);

Thisоднако приводит к этой ошибке:

System.NotSupportedException: 'Указанный член типа' GetLatestTransaction 'не поддерживается в LINQ to Entities.Поддерживаются только инициализаторы, элементы сущностей и свойства навигации сущностей. '

Есть ли способ достичь этого без сохранения другого отношения к последней транзакции для пользователя и необходимости обновлять его каждый раз, когда естьновая транзакция?

Редактировать: Я также хотел бы сделать это, как указано выше, чтобы избежать повторного запроса к базе данных, я хочу, чтобы все это было сделано за один раз для повышения производительности.

1 Ответ

0 голосов
/ 11 июня 2018

Ваш класс ApplicationUser представляет таблицу в базе данных.Он не отражает использование данных в таблице.

Довольно многие считают хорошей практикой отделить структуру базы данных от использования данных.Это разделение довольно часто выполняется с использованием шаблона хранилища.Репозиторий является абстракцией внутренней структуры данных базы данных.Он позволяет добавлять функциональность к вашим классам, не требуя этой функциональности в классах элементов управления, которые взаимодействуют с базой данных.

Существует множество статей о хранилище. Этот помог мне понять, какую функциональность я должен добавить в классы своей сущности, а какие в хранилище.

Так что вам понадобится класс, который представляет элементы в вашей таблице базы данных итот, который представляет applicationUsers только с их LatestTransaction

Класс, который представляет таблицу базы данных:

class ApplicationUser : IdentityUser
{
    public int Id {get; set;}
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public virtual List<TransactionModel> Transactions { get; set; }
}

ApplicationUser с последней транзакцией

class AppicationUserExt : <base class needed?>
{
    public int Id {get; set;}
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public TransactionModel LatestTransaction { get; set; }
}

Функция для получения вашего расширенного ApplicationUser - это функция расширения вашего ApplicationUser.Входные данные: IQueryable<ApplicationUser Выходные данные: IQueryable<ApplicationUserExt>

static class MyDbContextExtensions
{
    // returns ne ApplicationUserExt for every ApplicationUser
    public IQueryable<ApplicationUserExt> ToExtendedUsers(this IQueryable<ApplicationUser> applicationUsers)
    {
        return applicationUsers
            .Select(user => new ApplicationUserExt()
            {
               Id = user.Id,
               FirstName = user.FirstName,
               LastName = user.LastName,
               LatestTransaction = user.Trnasactions
                   .OrderByDescenting(transaction => transaction.CreationDate)
                    .FirstOrDefault(),
            }
        }
    }
}

Поэтому, когда у вас есть запрос с нужными вам ApplicationUsers, вы можете использовать ToExtendedUsers(), чтобы получить расширенные suers

using (var dbContext = new MyDbContext(...))
{
    // you wanted to have a query like:
    var result dbContext.ApplicationUsers
        .Where(user => user.FirstName = "John"
                    && user.LastName = "Doe");

    // you'll have to add ToExtendedUsers:
    var result = dbContext.ApplicationUsers
        .Where(user => user.FirstName = "John"
                    && user.LastName = "Doe");
        .ToExtendedUsers();
}

Поскольку результат по-прежнему является IQueryable, запрос еще не выполнен.Вы все еще можете добавить операторы LINQ до того, как запрос будет выполнен:

var result2 = result
    .Where(user.LatestTransaction.Year == 2018)        
    .GroupBy(user => user.LatestTransaction.Date)
    .OrderBy(group => group.Key)
    .Take(10)
    .ToList();

Вы видите, что вы все еще можете выполнять все виды LINQ, если это ApplicationUser.Как только вам понадобится LatestTransaction, вы преобразуете его в ApplicationUserExt и продолжаете объединять свои операторы linq.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...