我正在尝试在我的代码第一个EF模型的属性中定义一个lambda查询,如下所示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);
然而,这会导致此错误:
System.NotSupportedException:'LINQ to Entities中不支持指定的类型成员'GetLatestTransaction'。仅支持初始值设定项,实体成员和实体导航属性。'
是否有某种方法可以实现这一目标,而无需在用户上存储与最新交易的其他关系,并且每次有新交易时都必须更新它?
编辑:我还想像上面那样做,以避免对数据库进行另一次查询,我希望一次性完成以提高性能。
答案 0 :(得分:2)
您的ApplicationUser
类表示数据库中的表。它不代表表中数据的用法。
相当多的人认为将数据库结构与数据的使用分开是一种好习惯。这种分离通常使用存储库模式完成。存储库是数据库内部数据结构的抽象。它允许您向类添加功能,而无需在与数据库通信的控件类中要求此功能。
有很多关于存储库的文章。 This one帮助我理解了我应该在实体框架类中以及存储库中的哪些功能。
所以你需要一个代表数据库表中元素的类和一个代表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();
你知道,只要它是ApplicationUser
,你仍然可以做各种LINQ。只要您需要LatestTransaction
,就可以将其转换为ApplicationUserExt
并继续连接您的linq语句。