[英]Subquery with Entity Framework
I'm porting a subsystem from NHibernate to Entity Framework and want to see the best way to port the following query to EF .我正在将一个子系统从NHibernate移植到实体框架,并希望看到将以下查询移植到EF的最佳方法。
var date = DateTime.Now; // It can be any day
AccountBalanceByDate abbd = null;
var lastBalanceDateByAccountQuery = QueryOver.Of<AccountBalanceByDate>()
.Where(x => x.AccountId == abbd.AccountId && x.Date < date)
.Select(Projections.Max<AccountBalanceByDate>(x => x.Date));
var lastBalances = session.QueryOver<AccountBalanceByDate>(() => abbd)
.WithSubquery.WhereProperty(x => x.Date).Eq(lastBalanceDateByAccountQuery)
.List();
The account balance class is:账户余额类为:
public class AccountBalanceByDate
{
public virtual int Id { get; set; }
public virtual int AccountId { get; set; }
public virtual DateTime Date { get; set; }
public virtual decimal Balance { get; set; }
}
The table is:表是:
CREATE TABLE [dbo].[AccountBalanceByDate]
(
[Id] int NOT NULL,
[AccountId] int NOT NULL,
[Date] [datetime] NOT NULL,
[Balance] [decimal](19, 5) NOT NULL,
PRIMARY KEY CLUSTERED
(
[Id] ASC
)
)
A sample data is (using numeric ids for better understanding):示例数据是(使用数字 ID 以便更好地理解):
Id | Date | Account | Balance
------------------------------------
1 | 2014-02-01 | 101 | 1390.00000
2 | 2014-02-01 | 102 | 1360.00000
3 | 2014-02-01 | 103 | 1630.00000
4 | 2014-02-02 | 102 | 1370.00000
5 | 2014-02-02 | 103 | 1700.00000
6 | 2014-02-03 | 101 | 1490.00000
7 | 2014-02-03 | 103 | 1760.00000
8 | 2014-02-04 | 101 | 1530.00000
9 | 2014-02-04 | 102 | 1540.00000
The AccountBalanceByDate entity hold the account balance in a specific day. AccountBalanceByDate实体持有特定日期的账户余额。 If a day doesn't have a transaction, that day will not have an AccountBalanceByDate and we should look for the previous days to see the balance for that account.
如果一天没有交易,那一天将没有AccountBalanceByDate ,我们应该查找前几天以查看该帐户的余额。
If I query with the date 2014-02-01 I should get:如果我查询日期为2014-02-01,我应该得到:
No results
If I query with the date 2014-02-02 I should get:如果我查询日期为2014-02-02,我应该得到:
1 | 2014-02-01 | 101 | 1390.00000
2 | 2014-02-01 | 102 | 1360.00000
3 | 2014-02-01 | 103 | 1630.00000
If I query with the date 2014-02-03 I should get:如果我查询日期为2014-02-03,我应该得到:
1 | 2014-02-01 | 101 | 1390.00000
4 | 2014-02-02 | 102 | 1370.00000
5 | 2014-02-02 | 103 | 1700.00000
If I query with the date 2014-02-04 I should get:如果我查询日期为2014-02-04,我应该得到:
4 | 2014-02-02 | 102 | 1370.00000
6 | 2014-02-03 | 101 | 1490.00000
7 | 2014-02-03 | 103 | 1760.00000
If I query with the date 2014-02-05 I should get:如果我查询日期为2014-02-05,我应该得到:
7 | 2014-02-03 | 103 | 1760.00000
8 | 2014-02-04 | 101 | 1530.00000
9 | 2014-02-04 | 102 | 1540.00000
I can do this in Entity Framework using raw SQL, but it is not the ideal.我可以使用原始 SQL 在实体框架中执行此操作,但这并不理想。
using (var context = new DbContext())
{
var lastBalances = context.AccountBalanceByDate.SqlQuery(
@"SELECT
*
FROM
[AccountBalanceByDate] AB
WHERE
DATE = (
SELECT
MAX(Date)
FROM
[AccountBalanceByDate]
WHERE
AccountId = AB.AccountId AND DATE < @p0
)", date).ToList();
}
It is preferred to go to database just one time, like in NHibernate and raw SQL, but using just linq , is it possible?最好只访问一次数据库,就像在NHibernate和原始 SQL 中一样,但是只使用linq ,这可能吗?
UPDATE:更新:
Fixed results in the question.问题中的固定结果。
SQL showing the sample query on GIST: https://gist.github.com/LawfulHacker/275ec363070f2513b887在 GIST 上显示示例查询的 SQL: https : //gist.github.com/LawfulHacker/275ec363070f2513b887
Entity Framework sample on GIST: https://gist.github.com/LawfulHacker/9f7bd31a21363ee0b646 GIST 上的实体框架示例: https : //gist.github.com/LawfulHacker/9f7bd31a21363ee0b646
The following query do exactly what I need with just one query to the database:以下查询正是我需要的,只需对数据库进行一次查询:
var accountBalance = context
.AccountBalanceByDate
.Where(a =>
a.Date == context.AccountBalanceByDate
.Where(b => b.AccountId == a.AccountId && b.Date < date).Max(b => b.Date));
Thanks @AgentShark for the help.感谢@AgentShark 的帮助。
The code is on GIST: https://gist.github.com/sergiogarciadev/9f7bd31a21363ee0b646代码在 GIST 上: https : //gist.github.com/sergiogarciadev/9f7bd31a21363ee0b646
Finally, a solution.最后,一个解决方案。 :)
:)
var date = DateTime.Now; // It can be any day
var lastBalances = (from a in context.AccountBalanceByDate
where a.Date < date
group a by new {a.AccountId} into g
select g.OrderByDescending(a => a.Date).FirstOrDefault() into r
select new
{
Id = r.Id,
AccountId = r.AccountId,
Date = r.Date,
Balance = r.Balance
}).ToList();
You wanted it in LINQ, but personally, I might of kept the SQL for maintainability.您希望在 LINQ 中使用它,但就个人而言,为了可维护性,我可能会保留 SQL。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.