Collection Creation/Design Question - c#

I need to be binding a collection to a GridView depending on the report type selected by the user.
Each report varies slightly but uses the same basic result set which has many columns. Before I bind I want to loop through the result set and copy to a simpler collection (3 string variables called 'column1', 'column2', 'column3').
Code:
namespace etc.etc.etc
{
public class ReportEntity
{
public string column1 { get; set; }
public string column2 { get; set; }
public string column3 { get; set; }
}
}
List<ReportEntity> a = new List<ReportEntity>();
ReportEntity[] b = new ReportEntity[results.Length];
for (int i = 0; i < results.Length; i++)
{
//a[i].column1 = results[i].class.desc;
//a[i].column2 = results[i].student.firstname;
//a[i].column3 = results[i].timescanned.ToString();
//b[i].column1 = results[i].class.desc;
//b[i].column2 = results[i].student.firstname;
//b[i].column3 = results[i].timescanned.ToString();
}
Uncommenting where I set values for a gives Index was out of range. Must be non-negative and less than the size of the collection..
Uncommenting where i set values for b gives Object reference not set to an instance of an object..
results definitely has many records. What could I be doing wrong?

You get IndexOutRangeException in the 1st case because you just created an instance of list but this list doesn't contain any elements.
You get NullReferenceException in the 2nd case because you just filled array with results.Length of nulls.
What you should do is to explicitly create instance of ReportEntity and put in the underlying data structure.
List<ReportEntity> a = new List<ReportEntity>();
ReportEntity[] b = new ReportEntity[results.Length];
for (int i = 0; i < results.Length; i++)
{
a.Add(new ReportEntity() {column1 = results[i].class.desc,
column2 = results[i].student.firstname,
column3 = results[i].student.firstname }
b[i] = new ReportEntity() {column1 = results[i].class.desc,
column2 = results[i].student.firstname,
column3 = results[i].student.firstname }
}
Or you can you LINQ with Select extenssion method to like it's mentioned in another answer.

To add value to a List use the Add method.
Alternatively, use the select from LINQ:
var a = results.Select(r => new ReportEntity {
column1 = r.class.desc,
column2 = r.student.firstname,
column3 = r.timescanned.ToString()
}).ToList();

Related

How to loop list class

I have below class. And data is serialized using JsonConvert.DeserializeObject. The data is returning from list. But I want to loop using for or for each. Please advice.
Thank you.
var result = client.getInvocieLine
(call Context);
string strResultJson = JsonConvert.SerializeObject(result);
System.IO.File.WriteAllText(#"D:\jsondata\invoicedata.json", strResultJson);
string fileName = #"D:\jsondata\invoicedata.json";
string jsonText = System.IO.File.ReadAllText(fileName)
List<EInvoiceModel.Class1> data = Newtonsoft.Json.JsonConvert.DeserializeObject<List<EInvoiceModel.Class1>>(jsonText);
EInvoiceModel.Invoiceline invoicelined = new EInvoiceModel.Invoiceline();
for(int i=0; i < data.Count; i++)
{
invoicelined.parmItemId = data[i].invoiceLines[i].parmItemId; //Its bring only one record. I need all record from data. Please advice.
}
return Ok(invoicelined);
Please find my EInvoiceModel contains below structure, Which i designed as per my json response. yes I need same index for data and invoiceLines in data[i].invoiceLines[i]. How can I get this to return all values. Index currently pointing only one record and return one record. If I change position its return another record. But I need all please.
public class Class1
{
public Invoiceline[] invoiceLines { get; set; }
public string parmCustName { get; set; }
public DateTime parmInvoiceDate { get; set; }
} public class Invoiceline
{
public string parmItemId { get; set; }
public string parmItemNameDisplay { get; set; }
public float parmQty { get; set; }}
Please find my json structure. I wist to repeat all parameter-ids from json response.
{"invoiceLines":[{"parmCurrencyCode":null,"parmCustExchRate":0.0,"parmInvoiceId":null,"parmItemId":null,"parmItemNameDisplay":null,"parmQty":0.0,"parmSalesLinePercent":0.0,"parmSalesUnit":null,"parmdiscountAmount":0.0,"parmnetTotal":0.0,"parmsalesPrice":0.0,"parmsalesTotal":0.0,"parmtotalItemsLineDisc":0.0,"parmtotalTaxableFees":0.0}],"parmCustName":null,"parmInvoiceDate":"0001-01-01T00:00:00","parmInvoiceId":null,"parmSalesId":null,"parmnetAmount":0.0,"parmtotalAmount":0.0,"parmtotalAmountWithDisc":0.0,"parmtotalItemsDiscountAmount":0.0,"parmtotalSalesAmount":0.0}
Please I want return all parmItemId below way. I don't want damage my json structure.
EInvoiceModel.Class1 ds = new EInvoiceModel.Class1();
List<EInvoiceModel.Class1> data = Newtonsoft.Json.JsonConvert.DeserializeObject<List<EInvoiceModel.Class1>>(jsonText);
// List<EInvoiceModel.Invoiceline> data = Newtonsoft.Json.JsonConvert.DeserializeObject<List<EInvoiceModel.Invoiceline>>(jsonText);
for (int i = 0; i < data.Count; i++)
{
ds.invoiceLines = new List<EInvoiceModel.Invoiceline>
{
new EInvoiceModel.Invoiceline
{
parmItemId = data[i].invoiceLines[i].parmItemId
}
};
}
return Ok(ds);
You have used to Generic list
To get all list
List<EInvoiceModel.Invoiceline> data = Newtonsoft.Json.JsonConvert.DeserializeObject<List<EInvoiceModel.Invoiceline>>(jsonText);
List<EInvoiceModel.Invoiceline> invoicelines = new List<EInvoiceModel.Invoiceline>();
for(int i=0; i < data.Count; i++)
{
invoicelines.Add(new EInvoiceModel.Invoiceline()
{
parmItemId = data[i].parmItemId
});
}
return Ok(invoicelines);
You now have this:
EInvoiceModel.Class1 ds = new EInvoiceModel.Class1();
for (int i = 0; i < data.Count; i++)
{
ds.invoiceLines = new List<EInvoiceModel.Invoiceline>
{
new EInvoiceModel.Invoiceline
{
parmItemId = data[i].invoiceLines[i].parmItemId
}
};
}
This means that on every iteration you overwrite that ds.invoiceLines with a new list, containing a single item. So you end up with only the last one.
A possibly better way would be this:
EInvoiceModel.Class1 ds = new EInvoiceModel.Class1();
ds.invoiceLines = new List<EInvoiceModel.Invoiceline>(); // create a list once
for (int i = 0; i < data.Count; i++)
{
// add one item to that list
ds.invoiceLines.Add(new EInvoiceModel.Invoiceline
{
parmItemId = data[i].invoiceLines[i].parmItemId
}
);
}
This way you assign a new (empty) list once (you can skip this when invoiceLines already contains an empty list, after you created a new Class1).
And then, in the loop, you don't assign a new list, but just add a new item to that existing list. At the end, you get a list with as many items as there are in your input data.
By the way, this assumes that you really need to make a list of data[i].invoiceLines[i].parmItemId. I find it curious that for data[3] you need an invoiceLines[3] and for data[7] an invoiceLines[7]. I would expect one loop through all data and then an inner loop over all its invoiceLines. But you know your data best.
Apparently, you do need to loop over the inner objects. So modify that code like this:
EInvoiceModel.Class1 ds = new EInvoiceModel.Class1();
ds.invoiceLines = new List<EInvoiceModel.Invoiceline>(); // create a list once
// loop over all "data" items
for (int i = 0; i < data.Count; i++)
{
// then loop over the invoiceLines inside the current data item
for (int j = 0; j < data[i].invoiceLines.Count(); j++)
{
// add one item to that list
ds.invoiceLines.Add(new EInvoiceModel.Invoiceline
{
parmItemId = data[i].invoiceLines[j].parmItemId
}
);
}
}
Note that I still use index i in data[i] from the outer loop, but now use index j in invoiceLines[j] from the inner loop.

How to get all the values from an SQL Query C#

I have used String Builder to generate a RAW SQL QUERY in C#.
List<string> columns = new List<string>();
columns.Add("id");
columns.Add("Temp");
StringBuilder SqlStatement = new StringBuilder();
SqlStatement.Append("Select ");
for (int i = 0; i < columns.Count; i++)
{
if (i == columns.Count - 1)
{
SqlStatement.Append(columns[i]);
}
else
{
SqlStatement.Append(columns[i]);
SqlStatement.Append(",");
}
}
SqlStatement.Append(" FROM graph_update");
var ctx = new graphDBContext();
var result = ctx.Database.SqlQuery<graphDBContext>(SqlStatement.ToString()).ToList();
This translates into SELECT id,Temp FROM graph_update
And the result gives me
id = 1, temp = 20
id = 2 temp = 30
How do I get all these values????
I'm too use to:
foreach(var item in result)
{
item.id = id;
item.temp = temp;
}
But it won't let me.
EDIT:
Sorry but I'm not sure what you mean. Here is my debugger
Try to use foreach like this if theres no error return
foreach(var v in result)
{
String v0 = v[0].ToString();
String v1 = v[1].ToString();
}
Assuming you have EF > 6, then the ctx.Database.SqlQuery, according to the method documentation:
Creates a raw SQL query that will return elements of the given generic type.
The type can be any type that has properties that match the names of the columns returned from the query, or can be a simple primitive type. The type does not have to be an entity type. The results of this query are never tracked by the context even if the type of object returned is an entity type.
With that in mind you can do something like this:
public class GraphUpdateResult
{
public int Id {get; set;}
public decimal Temp {get; set;}
}
Then in your current method:
var result = ctx.Database.SqlQuery<GraphUpdateResult>SqlStatement.ToString()).ToList();
foreach (var graphResult in result)
{
Console.WriteLine(graphResult.Id);
Console.WriteLine(graphResult.Temp);
}
You can add more columns to the GraphUpdateResult class for EF to bind to, even if in some queries you don't specify them in the select statement.
I hope this helps.
foreach(var item in result)
{
var id = item.id;
var temp = item.temp;
}
in your code above, you are trying to assign the values to the item, instead of retrieving.
You can use a ORM-Mapper like
https://stormy.codeplex.com/SourceControl/latest#Stormy.cs
It is a very light Mapper and you can look how it works.
It maps the reader Data to the Object data:
public class CatMapper : ISelectable<Cat>
{
public Cat ApplySelect(IDataReader reader)
{
return new Cat()
{
Name = reader["name"].ToString(),
Weight = (float)reader["weight"]
};
}
}

How to delete duplicates from structure array with int and string components

In my project I have
struct Cities{public int Name;public int n}
int n represents the population of a city.
I also have cities[] c;, that array will be filled with names and number of citizens in city.
Example:
c[0].Name="New York";c[0].n=845698;
I need to write a method that will erase all cities from the array which have same names (if there is some) and to add their population to first one.
This should do it:
struct Cities
{
public string name;
public int n;
}
[Test]
public void SomeMethod()
{
Cities[] c = new Cities[7];
c[0].name = "new york";
c[0].n = 10;
c[1].name = "detroit";
c[1].n = 20;
c[2].name = "las vegas";
c[2].n = 30;
c[3].name = "new york";
c[3].n = 40;
c[4].name = "detroit";
c[4].n = 50;
c[5].name = "chicago";
c[5].n = 60;
c[6].name = "chicago";
c[6].n = 70;
c = c.GroupBy(ct => ct.name)
.Select(cl => new Cities
{
name = cl.First().name,
n = cl.Sum(ct => ct.n)
}).ToArray();
foreach (var city in c)
{
Console.WriteLine($"city={city.name}, pop={city.n}");
}
}
If the situation is just as simple as you describe, you might want to consider a
Dictionary<string, int>
You would then never add a duplicate city, rather if the city already existed (use trygetvalue(key, out value) or something) you would simply add the population.
Otherwise you are stuck with a simple search to find duplicates, and a routine which combines the duplicates and removes one of them.

Index was out of range. Must be non-negative and less than the size of the collection

I am new in generic collections
I have one class .The class name is ReportSubCategoryModel
these are that class properties
public class ReportSubCategoryModel
{
public string ReporTitle { get; set; }
public string ReporStatus { get; set; }
public string ReportDescription { get; set; }
public int ReporSubCategoryId { get; set; }
public IList<ReportSubCategoryModel> ReportSubCategoryModelList { get; set; }
}
I want to set the lot of values in this class properties from database . So i assigned a list of that class
IList<ReportSubCategoryModel> reportSubCategoryModel = new List<ReportSubCategoryModel>();
Now I want to set a values inside of for loop
IList<ReportSubCategory> reportSubCategory = datamodel.ReportSubCategory.Where(r => r.ReportCategoryId == reportCategoryId).ToList();
for (int i = 0; i < reportSubCategory.Count; i++)
{
int reportSubCategoryId = reportSubCategory[i].ReportSubCategoryId;
ReportStatu reportStatus =
datamodel.ReportStatus.SingleOrDefault(
r => r.ReportSubCategoryId == reportSubCategoryId);
if (reportStatus == null)
{
reportSubCategoryModel[i].ReportDescription = "Dis";**//This line threw the error**
reportSubCategoryModel[i].ReporStatus = "Not Available";
reportSubCategoryModel[i].ReporTitle = reportSubCategory[i].ReportSubCategoryName;
reportSubCategoryModel[i].ReportSubCategoryModelList.Add(reportSubCategoryModel[i]);
}
else
{
reportSubCategoryModel[i].ReportDescription = "Dis";
reportSubCategoryModel[i].ReporStatus = "Available For " + reportStatus.ReportStatusDescription;
reportSubCategoryModel[i].ReporTitle = reportSubCategory[i].ReportSubCategoryName;
reportSubCategoryModel[i].ReporSubCategoryId = reportSubCategoryId;
reportSubCategoryModel[i].ReportSubCategoryModelList.Add(reportSubCategoryModel[i]);
}
}
return reportSubCategoryModel.ToList();
But it's not working.
This line reportSubCategoryModel[i].ReportDescription = "Dis"; give's the error for Index was out of range. Must be non-negative and less than the size of the collection.
You can see this problem and my code from below image.Please zoom your browser (cntrl+Up Mouse Scrolling)
how can i solve this problem ?
I'm not entirely sure what the whole logic is meant to be, but this is how I feel the code should look like:
IList<ReportSubCategory> reportSubCategory = datamodel.ReportSubCategory
.Where(r => r.ReportCategoryId == reportCategoryId)
.ToList();
foreach (var subCategory in reportSubCategory)
{
int reportSubCategoryId = subCategory.ReportSubCategoryId;
ReportStatus reportStatus = datamodel.ReportStatus
.SingleOrDefault(r => r.ReportSubCategoryId == reportSubCategoryId);
if (reportStatus == null)
{
var model = new ReportSubCategoryModel();
model.ReportDescription = "Dis";
model.ReporStatus = "Not Available";
model.ReporTitle = subCategory.ReportSubCategoryName;
// Not sure what this is.
//model.ReportSubCategoryModelList.Add(reportSubCategoryModel[i]);
reportSubCategoryModel.Add(model);
}
else
{
var model = new ReportSubCategoryModel();
model.ReportDescription = "Dis";
model.ReporStatus = "Available For " + reportStatus.ReportStatusDescription;
model.ReporTitle = subCategory.ReportSubCategoryName;
model.ReporSubCategoryId = reportSubCategoryId;
// Not sure what this is either.
//reportSubCategoryModel[i].ReportSubCategoryModelList.Add(reportSubCategoryModel[i]);
reportSubCategoryModel.Add(model);
}
}
return reportSubCategoryModel;
Basically, you new up a model, set the properties and then Add that to the model list; based on iterating the sub category list.
However, I'm not sure what the whole nested list thing is about (the code I commented out).
Also, this code can be further trimmed, but I'll leave that out for now so as not to depart too much from the provided code.
Create a nested loop with in your main loop.With reportSubCategoryModel.Count.
you are treating list as an array.
something similar to following could replace the assigning section
var temp = new ReportSubCategoryModel();
temp.ReportDescription = "dis";
....
reportSubCategoryModel.Add(temp);
should sort the issue.
As far as I can see you have only created the list of reportSubCategoryModel and not yet populated it.
A list does not pre-populate with empty values and will therefore have a length of zero after initialisation. If you with to add new values you need to create your ReportSubCategoryModel object and then add it to the List.
Instead of trying to edit the values of the list;
reportSubCategoryModel[i].ReportDescription = "Dis";
Create the ReportSubCategoryModel object first, fill the data and the use the List.Add method to add it to your List.
ReportSubCategoryModel reportSubCategoryModelObject = new ReportSubCategoryModel();
reportSubCategoryModelObject.ReportDescription = "Dis";**//This line threw the error**
reportSubCategoryModelObject.ReporStatus = "Not Available";
reportSubCategoryModelObject.ReporTitle = reportSubCategory[i].ReportSubCategoryName;
reportSubCategoryModel.Add(reportSubCategoryModelObject);

remove list-items with Linq when List.property = myValue

I have the following code:
List<ProductGroupProductData> productGroupProductDataList = FillMyList();
string[] excludeProductIDs = { "871236", "283462", "897264" };
int count = productGroupProductDataList.Count;
for (int removeItemIndex = 0; removeItemIndex < count; removeItemIndex++)
{
if (excludeProductIDs.Contains(productGroupProductDataList[removeItemIndex].ProductId))
{
productGroupProductDataList.RemoveAt(removeItemIndex);
count--;
}
}
Now i want to do the same with linq. Is there any way for this?
The second thing would be, to edit each List-Item property with linq.
you could use RemoveAll.
Example:
//create a list of 5 products with ids from 1 to 5
List<Product> products = Enumerable.Range(1,5)
.Select(c => new Product(c, c.ToString()))
.ToList();
//remove products 1, 2, 3
products.RemoveAll(p => p.id <=3);
where
// our product class
public sealed class Product {
public int id {get;private set;}
public string name {get; private set;}
public Product(int id, string name)
{
this.id=id;
this.name=name;
}
}
Firstly corrected version of your current code that won't skip entries
List<ProductGroupProductData> productGroupProductDataList = FillMyList();
string[] excludeProductIDs = { "871236", "283462", "897264" };
int count = productGroupProductDataList.Count;
for (int removeItemIndex = 0; removeItemIndex < count; removeItemIndex++)
{
while (removeItemIndex < count && excludeProductIDs.Contains(productGroupProductDataList[removeItemIndex].ProductId)) {
productGroupProductDataList.RemoveAt(removeItemIndex);
count--;
}
}
}
This linq code would do the job.
List<ProductGroupProductData> productGroupProductDataList = FillMyList();
string[] excludeProductIDs = { "871236", "283462", "897264" };
productGroupProductDataList=productGroupProductDataList.Where(x=>!excludedProductIDs.Contains(x.ProductId)).ToList();
Alternatively using paolo's answer of remove all the last line would be would be
productGroupProductDataList.RemoveAll(p=>excludedProductIDs.Contains(p=>p.ProductId));
What you mean by "The second thing would be, to edit each List-Item property with linq."?
As per your comment here's a version that creates a set that excludes the elements rather than removing them from the original list.
var newSet = from p in productGroupProductDataList
where !excludeProductIDs.Contains(p.ProductId))
select p;
The type of newSet is IEnumerable if you need (I)List you can easily get that:
var newList = newSet.ToList();

Categories