2014-05-15 122 views
9

我從移植子系統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(); 

帳戶餘額類是:

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; } 
} 

該表是:

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 
    ) 
) 

的採樣數據被(使用數字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實體在特定日期持有賬戶餘額。如果某一天沒有交易,那一天將不會有AccountBalanceByDate,我們應該查看前幾天以查看該帳戶的餘額。

如果我有日期2014年2月1日查詢我應該得到:

No results 

如果我與日期查詢2014年2月2日我應該得到:

1 | 2014-02-01 | 101  | 1390.00000 
2 | 2014-02-01 | 102  | 1360.00000 
3 | 2014-02-01 | 103  | 1630.00000 

如果我與日期查詢2014年2月3日我應該得到:

1 | 2014-02-01 | 101  | 1390.00000 
4 | 2014-02-02 | 102  | 1370.00000 
5 | 2014-02-02 | 103  | 1700.00000 

如果我有日期2014年2月4日查詢我應該得到:

4 | 2014-02-02 | 102  | 1370.00000 
6 | 2014-02-03 | 101  | 1490.00000 
7 | 2014-02-03 | 103  | 1760.00000 

如果我與日期查詢2014-02-05我應該得到:

7 | 2014-02-03 | 103  | 1760.00000 
8 | 2014-02-04 | 101  | 1530.00000 
9 | 2014-02-04 | 102  | 1540.00000 

我可以在Entity Framework中使用原始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(); 
} 

最好是去數據庫只是一個時間,像NHibernate的和原始SQL,但只使用LINQ ,這可能嗎?

UPDATE:

在問題修復的結果。

SQL表示上GIST示例查詢:https://gist.github.com/LawfulHacker/275ec363070f2513b887

上GIST實體框架樣品:https://gist.github.com/LawfulHacker/9f7bd31a21363ee0b646

+0

自己的SQL查詢不會產生你在你的問題給出如下結果!查詢2014-02-01不會返回任何結果!首先修復你的查詢。 –

+0

@AgentShark,請注意,我有一個引用頂部表的子查詢,它爲每一行都執行該操作。然後,爲每一行獲取其帳戶ID並獲取最大日期。它將所有結果返回給每個帳戶的最大日期,每個帳戶的最大日期可能不同。這是個問題,我的樣本是正確的,當你指出它不正確時,我再次檢查它。 – LawfulHacker

+0

我得到你想要做的,但我在SQL Server 2008中輸入了你的確切數據並運行了你的查詢。 '2014-02-01'不會返回任何內容。 '2014-02-02'返回Ids 3,2,1。 '2014-02-03'返回Ids 5,4,1。 '2014-02-04'返回Ids 7,4,6​​。 –

回答

18

下面的查詢做的正是我需要的只有一個數據庫查詢:

var accountBalance = context 
    .AccountBalanceByDate 
    .Where(a => 
     a.Date == context.AccountBalanceByDate 
      .Where(b => b.AccountId == a.AccountId && b.Date < date).Max(b => b.Date)); 

感謝@AgentShark的幫助。

的代碼是GIST:https://gist.github.com/LawfulHacker/9f7bd31a21363ee0b646

3

最後,一個解決方案。:)

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(); 

你想在LINQ,但個人而言,我可能會保持SQL的可維護性。

+0

我用您的解決方案更新了要點示例,請注意它仍然不正確。的確,我非常感謝你的幫助。 – LawfulHacker

+0

@SergioGarcia我不得不不同意你的先生,我從SQL中返回這個LINQ匹配ID。我只是硬編碼的日期。我在VS2013中根據您的測試數據對此進行了測試。 –

+0

請檢查要點。但我找到了一個解決方案。 – LawfulHacker