我有以下三种型号。我想加入并在我的MVC应用程序中将它们与LINQ分组,以获得所需的结果数据。
var query = from i in db.Invoices
join id in db.Invoice_Details
on i.INVOICENO equals id.INVOICENO
join m in db.Mixings
on id.INVOICEDETAILID equals m.INVOICEDETAILID into ms
from m in ms.DefaultIfEmpty()
group new { id,m } by new
{
INVOICENO = id.INVOICENO,
DATE = i.DATE
}
into temp
select new Invoice_List
{
ID = temp.Key.INVOICENO,
INVOICENO = temp.Key.INVOICENO,
CARET = temp.Sum(g => g.id.CARET),
DATE = temp.Key.DATE,
ISSUECARET = (decimal?)temp.Select(c => c.m.CARETUSED).DefaultIfEmpty(0).Sum() ?? 0,
AVAILABLECARET = ((decimal?)temp.Select(c => c.id.CARET).DefaultIfEmpty(0).Sum() ?? 0) - ((decimal?)temp.Select(c => c.m.CARETUSED).DefaultIfEmpty(0).Sum() ?? 0)
};
INVOICENO DATE
---------------------
1 2017-01-23 00:00:00
2 2017-01-23 00:00:00
INVOICEDETAILID INVOICENO CARET
----------------------------------------------
1 1 100.00
2 1 200.00
3 2 300.00
4 2 400.00
MIXINGNO INVOICEDETAILID CARETUSED
------------------------------------------------
1 1 50.00
1 2 100.00
2 1 25.00
2 2 50.00
现在我希望通过将这三个表与group by连接来跟踪结果数据。
预期结果
INVOICENO DATE TOTALCARET CARETUSEDCARET AVAILABLECARET
------------------------------------------------------------------------------------------
1 2017-01-23 00:00:00 300.00 225.00 75.00
2 2017-01-23 00:00:00 700.00 0.00 700.00
INVOICENO DATE TOTALCARET CARETUSEDCARET AVAILABLECARET
------------------------------------------------------------------------------------------
1 2017-01-23 00:00:00 600.00 225.00 375.00
2 2017-01-23 00:00:00 700.00 0.00 700.00
答案 0 :(得分:3)
我写了一个例子作为对我们的评论的回复,这可能无法解决您的所有问题,但可能是一个良好的开端。这是我的测试环境:
public class Invoice
{
public int InvoiceNo { get; set; }
public DateTime DateTime { get; set; }
}
public class InvoiceDetails
{
public int InvoiceDetailId { get; set; }
public int InvoiceNo { get; set; }
public decimal Caret { get; set; }
}
public class Mixing
{
public int MixingNo { get; set; }
public int InvoiceDetailId { get; set; }
public decimal CaretUsed { get; set; }
}
private static void ExecQuery()
{
var invoices = new List<Invoice>();
invoices.Add(new Invoice { InvoiceNo = 1, DateTime = new DateTime(2017, 1, 23) });
invoices.Add(new Invoice { InvoiceNo = 2, DateTime = new DateTime(2017, 1, 23) });
var invoiceDetails = new List<InvoiceDetails>();
invoiceDetails.Add(new InvoiceDetails { InvoiceDetailId = 1, InvoiceNo = 1, Caret = 100 });
invoiceDetails.Add(new InvoiceDetails { InvoiceDetailId = 2, InvoiceNo = 1, Caret = 200 });
invoiceDetails.Add(new InvoiceDetails { InvoiceDetailId = 3, InvoiceNo = 2, Caret = 300 });
invoiceDetails.Add(new InvoiceDetails { InvoiceDetailId = 4, InvoiceNo = 2, Caret = 400 });
var mixings = new List<Mixing>();
mixings.Add(new Mixing { MixingNo = 1, InvoiceDetailId = 1, CaretUsed = 50 });
mixings.Add(new Mixing { MixingNo = 2, InvoiceDetailId = 2, CaretUsed = 100 });
mixings.Add(new Mixing { MixingNo = 3, InvoiceDetailId = 1, CaretUsed = 25 });
mixings.Add(new Mixing { MixingNo = 4, InvoiceDetailId = 2, CaretUsed = 50 });
// select all from invoices
var query = from i in invoices
// join the details
join id in invoiceDetails on i.InvoiceNo equals id.InvoiceNo
// group the details on invoice
group id by new { i.InvoiceNo, i.DateTime } into ig
// again join the details (from the mixing)
join id in invoiceDetails on ig.Key.InvoiceNo equals id.InvoiceNo
// join the mixing
join mix in mixings on id.InvoiceDetailId equals mix.InvoiceDetailId into mix2 // store in temp for outer join
from mbox in mix2.DefaultIfEmpty()
// group mixing (and sum the caret of the previous group
group mbox by new { ig.Key.InvoiceNo, ig.Key.DateTime, TotalCaret = ig.Sum(item => item.Caret) } into igm
// calculate the caret used (because it is used twice in the results)
let caretUsedCaret = igm.Where(item => item != null).Sum(item => item.CaretUsed)
// select the results.
select new
{
igm.Key.InvoiceNo,
igm.Key.DateTime,
igm.Key.TotalCaret,
CaretUsedCaret = caretUsedCaret,
Available = igm.Key.TotalCaret - caretUsedCaret
};
foreach (var row in query)
{
Trace.WriteLine(row.ToString());
}
}
结果显示:
{ InvoiceNo = 1, DateTime = 23-Jan-17 00:00:00, TotalCaret = 300, CaretUsedCaret = 225, Available = 75 }
{ InvoiceNo = 2, DateTime = 23-Jan-17 00:00:00, TotalCaret = 700, CaretUsedCaret = 0, Available = 700 }
答案 1 :(得分:2)
哈哈:)我用方法链写了同样的东西......
public class Invoice
{
public int INVOICENO { get; set; }
public DateTime DATE { get; set; }
}
public class InvoiceDetail
{
public int INVOICEDETAILID { get; set; }
public int INVOICENO { get; set; }
public int CARET { get; set; }
}
public class Mixing
{
public int MIXINGNO { get; set; }
public int INVOICEDETAILID { get; set; }
public int CARETUSED { get; set; }
}
[Fact]
public void LinqTest()
{
List<int> ints = new List<int> {1,2,3};
List<Invoice> invoices = new List<Invoice>
{
new Invoice {INVOICENO = 1, DATE = DateTime.Parse("23/01/2017")},
new Invoice {INVOICENO = 2, DATE = DateTime.Parse("23/01/2017")}
};
List<InvoiceDetail> invoiceDetails = new List<InvoiceDetail>
{
new InvoiceDetail{ INVOICEDETAILID = 1, INVOICENO = 1, CARET = 100},
new InvoiceDetail { INVOICEDETAILID = 2, INVOICENO = 1, CARET = 200},
new InvoiceDetail { INVOICEDETAILID = 3, INVOICENO = 2, CARET = 300},
new InvoiceDetail {INVOICEDETAILID = 4, INVOICENO = 2, CARET = 400}
};
List<Mixing> mixings = new List<Mixing>
{
new Mixing {MIXINGNO = 1, INVOICEDETAILID = 1, CARETUSED = 50},
new Mixing {MIXINGNO = 1, INVOICEDETAILID = 2, CARETUSED = 100},
new Mixing {MIXINGNO = 2, INVOICEDETAILID = 1, CARETUSED = 25},
new Mixing {MIXINGNO = 2, INVOICEDETAILID = 2, CARETUSED = 50}
};
var q =
invoices.Join(invoiceDetails, i => i.INVOICENO, id => id.INVOICENO, (invoice, detail) => new {invoice, detail})
.GroupJoin(mixings, arg => arg.detail.INVOICEDETAILID, m => m.INVOICEDETAILID,
(arg, m) => new {arg.invoice, arg.detail, Mixings = m})
.GroupBy(arg => arg.invoice)
.Select(
g =>
new
{
g.Key.INVOICENO,
g.Key.DATE,
Tot_Caret = g.Sum(arg => arg.detail.CARET),
Tot_Used = g.Sum(arg => arg.Mixings.Sum(mixing => mixing.CARETUSED)),
Available = g.Sum(arg => arg.detail.CARET) - g.Sum(arg => arg.Mixings.Sum(mixing => mixing.CARETUSED))
});
}
答案 2 :(得分:2)
EF的最大特色之一是所谓的导航属性。在LINQ to Entities查询中使用时,它们提供必要的元数据,以便在将查询转换为SQL时构建必要的连接。并且允许您构建查询,就好像它们是在对象上运行一样,这基本上消除了考虑连接的需要,而是集中于您的逻辑。
假设您的模型是这样的(仅显示导航属性):
public class Invoice
{
// ...
public ICollection<InvoiceDetail> Details { get; set; }
}
public class InvoiceDetail
{
// ...
public ICollection<Mixing> Mixings { get; set; }
}
同样查看表格,似乎InvoiceNo
是Invoice
的PK。
在这种情况下,您甚至不需要GroupBy
。前两个字段来自Invoice
,另一个字段来自儿童Sum
:
var query =
from i in db.Invoices
let TOTALCARET = i.Details.Sum(d => (decimal?)d.CARET) ?? 0
let USEDCARET = i.Details.SelectMany(d => d.Mixings).Sum(m => (decimal?)m.CARETUSED) ?? 0
select new
{
i.INVOICENO,
i.DATE,
TOTALCARET,
USEDCARET,
AVAILABLECARET = TOTALCARET - USEDCARET
};
唯一的技巧是在使用Sum
函数时将非可空类型提升为可空,以便在源序列为空时避免异常。然后使用null-coalescing运算符在需要时将其转换为不可为空。
答案 3 :(得分:0)
如果有人使用LINQ解决方案,请在此处发布。 @Jeroen van Langen的答案非常接近但却给我错误。
通过一些修改和尝试,我至少解决了Raw SQLQuery的问题。 LINQ没有帮助我处理复杂和嵌套的查询。 以下是我非常熟悉的Raw SQL代码,它是一个临时解决方案。根据我的最终要求,我还添加了其他几张表。
使用RAW SQL QUERY的TEMP工作解决方案
var str = "select";
str += " a.ID,a.INVOICENO,a.TOTAL,a.CARET,a.DATE,a.PARTY,a.BROKER,";
str += " ISNULL(b.CARET,0) as ISSUECARET,";
str += " ISNULL(a.CARET,0) - ISNULL(b.CARET,0) as AVAILABLECARET";
str += " from";
str += " (";
str += " select";
str += " i.INVOICENO as ID,";
str += " i.INVOICENO,";
str += " i.DATE,";
str += " a.accountname as PARTY,";
str += " b.accountname as BROKER,";
str += " SUM(id.CARET) as CARET,";
str += " SUM(id.TOTAL) as TOTAL";
str += " from invoice i";
str += " inner";
str += " join Invoice_Details id";
str += " on i.INVOICENO = id.INVOICENO";
str += " inner join account a on a.ID=i.party inner join account b on b.ID=i.broker";
str += " group by";
str += " i.id,";
str += " i.INVOICENO,";
str += " i.DATE,";
str += " a.accountname,";
str += " b.accountname";
str += " )";
str += " as a";
str += " left join";
str += " (";
str += " select";
str += " id.INVOICENO,";
str += " SUM(m.caret) as CARET";
str += " from";
str += " Invoice_Details id";
str += " left";
str += " join";
str += " Mixing m";
str += " on id.ID = m.INVOICEDETAILID";
str += " group by id.invoiceno";
str += " )";
str += " as b";
str += " on a.INVOICENO = b.INVOICENO";
var query = db.Database.SqlQuery<Invoice_List>(str);