尝试使用方法创建联接的实体框架需要帮助

时间:2018-02-28 16:05:54

标签: c# entity-framework

我真的可以使用一些帮助,我有以下SQL查询可以工作,并一直试图将其转换为实体框架无济于事。我使用的是方法而不是其他选项,我认为这就是你说的。

无论如何SQL都是

SELECT c.ACCOUNTID,
       c.TOACCOUNTID,
       fa.ACCOUNTNAME, ta.ACCOUNTNAME,
       p.PAYEENAME

  FROM checking AS c
       LEFT JOIN
       ACCOUNT AS fa ON c.ACCOUNTID = fa.ACCOUNTID
       LEFT JOIN
       ACCOUNT AS ta ON c.TOACCOUNTID = ta.ACCOUNTID
       LEFT JOIN
       PAYEE AS p ON c.PAYEEID = p.PAYEEID
 WHERE c.ACCOUNTID == 1 OR 
       c.TOACCOUNTID == 1;

到目前为止,我已成功实现这一目标。

            var checking =
                db.Transactions
                .Where(item => item.ACCOUNTID == LookupAccount || item.TOACCOUNTID == LookupAccount)
                .GroupJoin(db.PAYEE,
                    transaction => transaction.PAYEEID,
                    payee => payee.PAYEEID,
                    (check, payee) => new { Payee = payee }
                ).SelectMany(
                    transaction => transaction.Payee.DefaultIfEmpty(),
                    (transaction, payee) => new { Payee = payee })

                .Select(item => new
                {
                    ToAccount = item.ToAccount.AccountName
                    FromAccount = item.FromAccount.AccountName
                    Withdrawal = 0,
                    Deposit = 0,
                    Payee = item.Payee.PAYEENAME
                }).ToList();

我现在遇到的问题是,我不确定我是否理解联接是如何以这种方式工作的,每当我试图让其他两个联接时,我最终都会落在我的脸上。

当我将此添加到上面的代码时,收款人部分出了问题,我不明白为什么。我知道它与select new {}部分有关,我真的可以使用一些帮助来理解它是如何工作的。

                .Join(db.ACCOUNT,
                    check => check.ACCOUNTID,
                    account => account.ACCOUNTID,
                    (check, fromaccount) => new { FromAccount = fromaccount }
                )

模型

交易

public partial class Transaction
{
    [Key]
    public int Id { get; set; }

    public int AccountID { get; set; }

    public int? ToAccountId { get; set; }

    public int PayeeId { get; set; }

    [Column(TypeName = "numeric")]
    public decimal TransAmount { get; set; }

    [Column(TypeName = "numeric")]
    public decimal ToTransAmount { get; set; }

    public virtual Account Account { get; set; }
}

帐户

public partial class Account
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Account()
    {
        Transaction = new HashSet<Transaction>();
    }

    [Key]
    public int AccountId { get; set; }

    [Required]
    [StringLength(150)]
    public string AccountName { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Transaction> Transaction { get; set; }
}

2 个答案:

答案 0 :(得分:0)

这不会作为评论,但它可能会让你更进一步。您的tx类中有2个FK,因此您需要2个导航属性:

public partial class Transaction
{
    public int Id { get; set; } // Key by convention

    public int FromAccountID { get; set; }
    public virtual Account FromAccount { get; set; }

    public int? ToAccountId { get; set; }
    public virtual Account ToAccount { get; set; }

    public int PayeeId { get; set; }
    public virtual Payee Payee { get; set; }

    public decimal TransAmount { get; set; }
    public decimal ToTransAmount { get; set; }
}

public partial class Account
{
    public Account()
    {
        Transaction = new HashSet<Transaction>();
    }

    public int AccountId { get; set; }  // Key by convention

    [Required]
    [StringLength(150)]
    public string AccountName { get; set; }

    [InverseProperty("FromAccount")]
    public virtual ICollection<Transaction> TransactionsFrom { get; set; }
    [InverseProperty("ToAccount")]
    public virtual ICollection<Transaction> TransactionsTo { get; set; }
}

现在您的查询变为:

var checking =
    db.Transactions
    .Include(tx => tx.Payee)
    .Include(tx => tx.FromAccount)
    .Include(tx => tx.ToAccount)
    .Where(tx => tx.FromAccountId == lookupAccountId || tx.ToAccountId == lookupAccountId)
    .Select(tx => new
    {
        ToAccountName = tx.ToAccount.AccountName
        FromAccountName = tx.FromAccount.AccountName
        Withdrawal = tx.ToTransAmount,
        Deposit = tx.TransAmount,
        PayeeName = tx.Payee.PAYEENAME
    }).ToList();

https://coding.abel.nu/2012/06/dont-use-linqs-join-navigate/

答案 1 :(得分:0)

我已经创建了这个作为答案,对于任何其他可能遇到此问题且正在学习语法的人。

我没有让它发挥作用的原因实际上是由于缺乏EF在加入时的实际效果。

Transactions
.Join(Accounts,
    tr => tr.AccountId,
    ac => ac.AccountId,
    (tr, ac) => new { Transaction = tr, ac})

.GroupJoin(Accounts,
    tr => tr.Transaction.ToAccountId,
    ta => ta.AccountId,
    (tr, ta) => new { Transaction = tr.Transaction, Account = ta, FromAccount = tr.ac})
    .SelectMany(
        transaction => transaction.Account.DefaultIfEmpty()
        ,(transaction, account) => new { tt = transaction.Transaction, ToAccount = account, FromAccount = transaction.FromAccount}
    )

.GroupJoin(Payees,
    tr => tr.tt.PayeeId,
    payee => payee.PAYEEID,
    (tr, payee) => new { Transaction = tr, Payee = payee })
    .SelectMany(
        transaction => transaction.Payee.DefaultIfEmpty(),
        (transaction, payee) => new {transaction = transaction.Transaction.tt, FromAccount = transaction.Transaction.FromAccount, ToAccount = transaction.Transaction.ToAccount, Payee = payee })

.Where (x=> x.FromAccount.AccountId == 1 || x.ToAccount.AccountId == 1)

.Select(item => new
    {
        item.transaction.Id,
        TransDate = item.transaction.TRANSDATE,
        Number = item.transaction.TransactionNumber,
        Payee = item.Payee.PAYEENAME,
        Status = item.transaction.Status,

        Category = item.transaction.CategoryId,

        FromAccount = item.FromAccount.AccountName,
        ToAccount = item.ToAccount.AccountName,
        Withdrawal = 0,
        Deposit = 0,
        Notes = item.transaction.Notes
    })

我不理解的部分是代码中的关系,来自连接以及Selects如何接管并通过对象创建层次结构。我真的希望我可以在这里使用导航,但是根据我对导航的理解,需要在列之间建立关系,并且几乎所有在这里连接的字段都可以为null,因此外键不能满足要求导航。

我仍然相信有更好的方法,但是现在我把它放在那些仍在学习并希望看到有效解决方案的人身上。