Override ToString() in LINQ Query???

P

Paolo

I want to format the output from LINQ queries. At the moment if I do ...

private void btnAllTransactions_Click(object sender, EventArgs e)
{
var query =
from trans in dataSet.Transaction
select new
{
trans.T_Date,
trans.T_PayeeId,
trans.T_Category,
trans.T_SubCategory,
trans.T_PayMethod,
trans.T_Amount
};

foreach (var item in query)
{
richtxbxAnalysis.AppendText(item.ToString() + "\n"); <<<<<
}
}

.... I get a default list, and I cannot apply formatting to the output.

I know that ToString() can be overridden as part of a class but how would I
achieve such an override in the example above? To which class, if any, would
I apply the override?

Thanks
 
G

Göran Andersson

Paolo said:
I want to format the output from LINQ queries. At the moment if I do ...

private void btnAllTransactions_Click(object sender, EventArgs e)
{
var query =
from trans in dataSet.Transaction
select new
{
trans.T_Date,
trans.T_PayeeId,
trans.T_Category,
trans.T_SubCategory,
trans.T_PayMethod,
trans.T_Amount
};

foreach (var item in query)
{
richtxbxAnalysis.AppendText(item.ToString() + "\n"); <<<<<
}
}

... I get a default list, and I cannot apply formatting to the output.

I know that ToString() can be overridden as part of a class but how would I
achieve such an override in the example above? To which class, if any, would
I apply the override?

Thanks

You can't override it in an anonymous class, as you don't have anywhere
to put the method declaration. You have to create a named class.

For example:

public class TransactionItem {

public DateTime Date { get; set; }
public int PayeeId { get; set; }
public string Category { get; set; }
public string SubCategory { get; set; }
public string PayMethod { get; set; }
public int Amount { get; set; }

public TransactionItem(DateTime date, int payeeId, string category,
string subCategory, string payMethod, int amount) {
Date = date;
PayeeId = payeeId;
Category = category;
SubCategory = subCategory;
PayMethod = payMethod;
Amount = amount;
}

public override string ToString() {
return Date.ToString("yyyy-MM-dd") + " " + Category + " " +
SubCategory + " " + Amount.ToString();
}

}


Then you just create instances of the class in the query, and you can
use the ToString method:

var query =
from trans in dataSet.Transaction
select new TransactionItem(trans.T_Date, trans.T_PayeeId,
trans.T_Category, trans.T_SubCategory, trans.T_PayMethod, trans.T_Amount);

foreach (TransactionItem item in query) {
richtxbxAnalysis.AppendText(item.ToString() + Environment.NewLine);
}
 
P

Paolo

Goran: thank you - I thought something like that would be necessary. The
example I posted was a pretty basic one. How would I use the TransactionItem
class with more complex queries e.g.

private void btnPayees_Click(object sender, EventArgs e)
{
var payeeQuery =
from trans in dataSet.Transaction // get all transactions
from c in dataSet.Category where trans.T_Category == c.C_Id
from s in dataSet.SubCategory where trans.T_SubCategory ==
s.S_Id
from p in dataSet.Payee where trans.T_PayeeId == p.P_Id

select new
{
p.P_Name,
c.C_Description,
s.S_Description,
trans.T_Amount
}
into startGroup

group startGroup by new
{
startGroup.P_Name,
startGroup.C_Description,
startGroup.S_Description
}
into secondGroup

select new
{
Payee = secondGroup.Key.P_Name,
Category = secondGroup.Key.C_Description,
SubCategory = secondGroup.Key.S_Description,
Count = secondGroup.Count(),
Sum = secondGroup.Sum(s => s.T_Amount),
Mean = (secondGroup.Sum(s => s.T_Amount)) /
(secondGroup.Count())
}
into thirdGroup

orderby thirdGroup.Payee,
thirdGroup.Category,
thirdGroup.SubCategory

select thirdGroup;
}
 
P

Paolo

It looks like I'll need a 'Transaction' class for each query, since the data
required differs.
 
G

Göran Andersson

Paolo said:
Goran: thank you - I thought something like that would be necessary. The
example I posted was a pretty basic one. How would I use the TransactionItem
class with more complex queries e.g.

private void btnPayees_Click(object sender, EventArgs e)
{

8< snip

You only need to create named classes for the classes that you need to
override the ToString method in.
 
G

Göran Andersson

Paolo said:
Goran: OK, so I just 'create' classes containing the data items I want to use?

Exactly. When you use an anonymous class, that is what the compiler does
for you in the background. You just have to write the code yourself instead.
 
P

Paolo

Goran: I've run into a problem trying to create a named class with a grouped
LINQ query and intermediate aggregations.

I created a class thus:

public class GroupedItem
{

string spacer = "\t"
public string CategoryDesc { get; set; }
public string SubCatDesc { get; set; }
public decimal Amount { get; set; }

public GroupedItem(string categoryDesc, string subCategoryDesc,
decimal amount)
{
CategoryDesc = c.C_Description,
SubCateDesc = s.S_Description,
Amount = trans.T_Amount
}

public string ToString(string decimalDisplayFormat)
{
return Category + spacer + SubCategory + spacer +
Amount.ToString(decimalDisplayFormat);
}
}

to use in the following LINQ query:

private void btnGroupedCategories_Click(object sender, EventArgs e)
{
var groupQuery =
from trans in dataSet.Transaction
from c in dataSet.Category where trans.T_Category == c.C_Id
from s in dataSet.SubCategory where trans.T_SubCategory ==
s.S_Id

select new GroupedItem
(
c.C_Description,
s.S_Description,
trans.T_Amount
)
into startGroup

group startGroup by new
{
startGroup.CategoryDesc,
startGroup.SubCatDesc
}
into secondGroup

select new
{
Category = secondGroup.Key.CategoryDesc,
SubCategory = secondGroup.Key.SubCatDesc,
Count = secondGroup.Count(),
Sum = secondGroup.Sum(s => s.Amount),
Mean = ( secondGroup.Sum(s =>
s.Amount))/(secondGroup.Count())
}
into thirdGroup

orderby thirdGroup.Category,
thirdGroup.SubCategory

select thirdGroup;

string headerText = "Column headers go here";
setRTBHeadings(headerText);

foreach (GroupedItem item in groupQuery)
{

richtxbxAnalysis.AppendText(item.ToString(decimalDisplayFormat) +
Environment.NewLine);
}
}

I am receiving an error regarding unable to convert anonymous type to
Grouped Item.

I'm assuming this is something to do with the

select new
{
Category = secondGroup.Key.CategoryDesc,
SubCategory = secondGroup.Key.SubCatDesc,
Count = secondGroup.Count(),
Sum = secondGroup.Sum(s => s.Amount),
Mean = ( secondGroup.Sum(s =>
s.Amount))/(secondGroup.Count())
}


I've got Category, SubCategory and Amount defined in my GroupedItem class
but I don't know how to deal with Count, Sum and Mean - I can't pass them as
parameters in the constructor since they don't exist at instanstiation. I've
also not been able to include thes in my ToString() method for the same
reason.

How do I solve this problem?
 
G

Göran Andersson

Paolo said:
Goran: I've run into a problem trying to create a named class with a grouped
LINQ query and intermediate aggregations.

I created a class thus:

public class GroupedItem
{

string spacer = "\t"
public string CategoryDesc { get; set; }
public string SubCatDesc { get; set; }
public decimal Amount { get; set; }

public GroupedItem(string categoryDesc, string subCategoryDesc,
decimal amount)
{
CategoryDesc = c.C_Description,
SubCateDesc = s.S_Description,
Amount = trans.T_Amount
}

public string ToString(string decimalDisplayFormat)
{
return Category + spacer + SubCategory + spacer +
Amount.ToString(decimalDisplayFormat);
}
}

to use in the following LINQ query:

private void btnGroupedCategories_Click(object sender, EventArgs e)
{
var groupQuery =
from trans in dataSet.Transaction
from c in dataSet.Category where trans.T_Category == c.C_Id
from s in dataSet.SubCategory where trans.T_SubCategory ==
s.S_Id

select new GroupedItem
(
c.C_Description,
s.S_Description,
trans.T_Amount
)
into startGroup

group startGroup by new
{
startGroup.CategoryDesc,
startGroup.SubCatDesc
}
into secondGroup

select new
{
Category = secondGroup.Key.CategoryDesc,
SubCategory = secondGroup.Key.SubCatDesc,
Count = secondGroup.Count(),
Sum = secondGroup.Sum(s => s.Amount),
Mean = ( secondGroup.Sum(s =>
s.Amount))/(secondGroup.Count())
}
into thirdGroup

orderby thirdGroup.Category,
thirdGroup.SubCategory

select thirdGroup;

string headerText = "Column headers go here";
setRTBHeadings(headerText);

foreach (GroupedItem item in groupQuery)
{

richtxbxAnalysis.AppendText(item.ToString(decimalDisplayFormat) +
Environment.NewLine);
}
}

I am receiving an error regarding unable to convert anonymous type to
Grouped Item.

I'm assuming this is something to do with the

select new
{
Category = secondGroup.Key.CategoryDesc,
SubCategory = secondGroup.Key.SubCatDesc,
Count = secondGroup.Count(),
Sum = secondGroup.Sum(s => s.Amount),
Mean = ( secondGroup.Sum(s =>
s.Amount))/(secondGroup.Count())
}


I've got Category, SubCategory and Amount defined in my GroupedItem class
but I don't know how to deal with Count, Sum and Mean - I can't pass them as
parameters in the constructor since they don't exist at instanstiation. I've
also not been able to include thes in my ToString() method for the same
reason.

How do I solve this problem?

You create a named class for the class that you select into the final
result, i.e. the last class in the query, not the first. The first two
classes are only used in temporary results to create the third result.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top