I have a class
public class Row : IExtensible
{
public Row();
[ProtoMember(1, IsRequired = true, Name = "key", DataFormat = DataFormat.Default)]
public byte[] key { get; set; }
[ProtoMember(2, Name = "values", DataFormat = DataFormat.Default)]
public List<Cell> values { get; }
}
I can populate manually using the following approach:
Edit :
//column and data are sample byte[] values
CellSet.Row row = new CellSet.Row { key = sampleKey };
Cell value = new Cell { column = column1, data = data1 };
row.values.Add(value);
I need to populate these values in LINQ,this is what I have been trying:
var result =
(
from a in firstrow
let valuesset = a.Split(',')
from l in valuesset
select new CellSet.Row
{
key = Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()),
//values = new List<Cell>() //Not possible since only get is there
}
).ToList();
How to add values to the object CellSet.Row?
I have also tried this
//Edit:
//Read the xml file row by row and process it
var result =
(
from a in firstrow
let valuesset = a.Split(',')
from l in valuesset
select new CellSet.Row
{
key = Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()),
//values = new List<Cell>() //Not possible since only get is there
}.values.Add(value12)
).ToList();
Getting an error in values like :
An expression of type 'string[]' is not allowed in a subsequent from clause with IEnumerable<>
You would do something like this:
Func<byte[], IEnumerable<Cell>, Row> create =
(k, cs) =>
{
CellSet.Row row = new CellSet.Row { key = k };
row.values.AddRange(cs);
return row;
};
var result =
(
from a in firstrow
let valuesset = a.Split(',')
from l in valuesset
select create(
Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()),
new [] { value12 })
).ToList();
Now, since your code wasn't clear as to how it should exactly work the answer isn't quite there either. But this should give you the basic idea.
Related
I need help on part of this code. I'm using a checkbox column in my DataGridView control. When I retrieve my data record, if a value exists then the checkbox should be checked, and if not it should remain unchecked. How to I accomplish that on a DataGridView with this kind of logic?
using (DataContext dtContext = new DataContext())
{
var query = (from i in dtContext.materialTBheader where i.proj == Proj_id select i);
foreach (var r in query)
{
if (!string.IsNullOrEmpty(r.materialheader_id.ToString()))
{
string[] row = { r.materialheader_id.ToString(), r.materialname, r.description, string.Format("{0:n2}", r.totalAmount), GetCount(r.materialname, txtMainProjectHeader_id, Convert.ToDecimal(r.totalAmount)), "", -- cell checkbox if record exist true checked if not false uncheck };
dGVMaterialHeaderList.Rows.Add(row);
}
}
}
It dosen't need to add your rows by foreach, use DataSource Property
Suppose you have a List of Person and you want to show in dataGridview, you have to option
1)add your column to data grid in visual studio properties window
2)add your column with coding
then map your data to grid
here is an simple example to help yo
public class Person
{
public int Id { get; set; }
public string LastName { get; set; }
public bool Married { get; set; }
}
private void Form1_Load(object sender, EventArgs e)
{
//your data from ef
var myData = new List<Person>
{
new Person{Id=1,LastName="A1",Married =true},
new Person{Id=1,LastName="A2",Married =false},
new Person{Id=1,LastName="A3",Married =true},
};
//your columns
var idColumn = new System.Windows.Forms.DataGridViewTextBoxColumn
{
Name = "Id",
HeaderText = "Id",
DataPropertyName = "Id"
};
var lastNameColumn = new System.Windows.Forms.DataGridViewTextBoxColumn
{
Name = "LastName",
HeaderText = "LastName",
DataPropertyName = "LastName"
};
var marriedColumn = new System.Windows.Forms.DataGridViewCheckBoxColumn
{
Name="Married",
HeaderText="Married",
DataPropertyName= "Married"
};
// add your columns to grid
dGVMaterialHeaderList.Columns.Add(idColumn);
dGVMaterialHeaderList.Columns.Add(lastNameColumn);
dGVMaterialHeaderList.Columns.Add(marriedColumn);
dGVMaterialHeaderList.AutoGenerateColumns = false;
//bind your data
dGVMaterialHeaderList.DataSource = myData;
}
In your case the answer is something like below:
using (DataContext dtContext = new DataContext())
{
var query = (from i in dtContext.materialTBheader where i.proj == Proj_id select i).ToList();
var gridData = query.Select(r=>new
{
materialheader_id = r.materialheader_id.ToString(),
r.materialname,
r.description,
totalAmount = string.Format("{0:n2}", r.totalAmount),
Count = GetCount(r.materialname, txtMainProjectHeader_id, Convert.ToDecimal(r.totalAmount)),
isExist = !string.IsNullOrEmpty(r.materialheader_id.ToString())?true:false
}).ToList();
dGVMaterialHeaderList.DataSource = gridData;
}
I don't know your data structure but I know this is not best approach you choose
I hope this can help you
I have a Datatable which is being added to List with specific format. Now as per my requirement I do not want to create generic list from a Class while preserving the format of my data but not able to do it. Below is my code
List<Data> datalist = new List<Data>();
for (int i = 0; i < dt.Rows.Count; i++)
{
Data dd1 = new Data();
dd1.ID = Convert.ToString(dt.Rows[i]["ID"]);
dd1.STATUS = Convert.ToString(dt.Rows[i]["Name"]);
dd1.TYPE = Convert.ToString(dt.Rows[i]["TYPE"]);
datalist.Add(dd1);
}
Is there a way to remove dependency of class Data from the above code keeping the format same?
You can use linq query on your dt like below and project your result into anonymous type like.
var datalist = (from r in dt.AsEnumerable()
select new
{
ID = r.Field<string>("ID"),
Name = r.Field<string>("Name"),
TYPE = r.Field<string>("TYPE"),
}).ToList();
If you want to get name for some Id from datalist then.
string name = datalist.Where(x => x.ID == "123").FirstOrDefault()?.Name;
You could use a dictionary in its place. No more Data class dependency, but the same basic data and format!
var datalist = new List<IDictionary<string, string>>();
for (var i = 0; i < dt.Rows.Count; ++i)
{
var data = new Dictionary<string, string>()
{
{ "ID", Convert.ToString(dt.Rows[i]["ID"]) },
{ "STATUS", Convert.ToString(dt.Rows[i]["Name"]) },
{ "TYPE", Convert.ToString(dt.Rows[i]["TYPE"]) }
};
datalist.Add(data);
}
Then you'd just access the values datalist[i]["ID"] instead of datalist[i].ID.
I have the following responses from the API. How can I group them into the following structure?
Student[]
- Name
- Classes[]
- ClassName
- ClassId
- ClassCategories[]
- CategoryName
- CategoryWeight
- Assignments[]
- AssignmentName
- Score
I was managed to group them until the "Classes" level but unable to get the ClassCategories for each of the classes
var data = (from result in results
group result by new { result.StudentId, result.FirstName, result.LastName, result.MiddleInitial }
into StudentGroup
select new GroupedStudent
{
StudentId = StudentGroup.Key.StudentId,
FullName = string.Format("{0} {1} {2}", StudentGroup.Key.FirstName, StudentGroup.Key.MiddleInitial, StudentGroup.Key.LastName).Replace(" ", " "),
Classes = from result in results
group result by new { result.ClassId, result.ClassName } into ClassGroup
select new groupedClass
{
ClassName = ClassGroup.Key.ClassName,
ClassId = ClassGroup.Key.ClassId,
ClassCategories = ...
})
}).ToList();
Can anyone please assists me? Thank you.
First, you have make ClassGroup from StudentGroup not from results.
Classes = from s in StudentGroup group result by new { s.ClassId, s.ClassName } into ClassGroup
The complete linq query is as follows:
var data =
(from result in results
group result by new { result.StudentId, result.FirstName, result.LastName, result.MiddleInitial } into StudentGroup
select new
{
StudentId = StudentGroup.Key.StudentId,
FullName = string.Format("{0} {1} {2}", StudentGroup.Key.FirstName, StudentGroup.Key.MiddleInitial, StudentGroup.Key.LastName).Replace(" ", " "),
Classes = (from s in StudentGroup
group s by new { s.ClassId, s.ClassName } into ClassGroup
select new
{
ClassId = ClassGroup.Key.ClassId,
ClassName = ClassGroup.Key.ClassName,
ClassCategories = (from c in ClassGroup
group c by new { c.CategoryName, c.CategoryWeight } into CategoryGroup
select new
{
CategoryName = CategoryGroup.Key.CategoryName,
CategoryWeight = CategoryGroup.Key.CategoryWeight,
Assignments = (from ct in CategoryGroup
group ct by new { ct.AssignmentName, ct.Score } into AssingnmentGroup
select new
{
AssignmentName = AssingnmentGroup.Key.AssignmentName,
Score = AssingnmentGroup.Key.Score
}).ToList()
}).ToList()
}).ToList()
}).ToList();
For example, if you want to access to the first Assignment's score, you can get it like this:
var student = data.FirstOrDefault();
var score = student.Classes[0].ClassCategories[0].Assignments[0].Score;
This is usually how I do It.
Create a class to store your data
Create a list of that class type
In your case instead of string dataRow maybe you can use a sub class
.
// get data from webservice
var json = webClient.DownloadString(url);
var values = JsonConvert.DeserializeObject<JArray>(json);
// create a list to save all the element
List<myClass> classList = new List<myClass>();
// process every row
foreach (string dataRow in values)
{
string[] dataField = dataRow.Split(',');
// have a constructor to assign each value to this element
myClass ctROW = new myClass(dataField);
classList.add(ctROW );
I have some working code that retrieves data from data base. It is interesting for me to get some better code for my solution. Are there some ways to combine two queries into one or something like this?
Dim customerTitlesAndIDs = contex.CustomerTable.Select(Function(row) New
With {.ID = row.ID, .CustomerTitle = row.Title}).ToList()
Dim cutomerIdPayment = contex.CustomerPayments.Select(Function(table) New
With
{
.ID = table.CustomerID,
.Range = table.PaymentsRange,
.Values = table.Values
}).ToList()
Dim customerInfos As New List(Of SCustomerInfo)
For Each customer In customerTitlesAndIDs
Dim cID As Integer = customer.ID
customerInfo.Add(New SCustomerInfo(CreateCustomerTable(), cID, customer.CustomerTitle))
For Each cutomerPayments In cutomerIdPayment
If cutomerPayments.ID = cID Then
Dim rangeValue(1) As Object
rangeValue(0) = cutomerPayments.Range
rangeValue(1) = cutomerPayments.Values
Dim dtRow As DataRow = customerInfos.Last().PaymentTable.NewRow()
dtRow.ItemArray = rangeValue
customerInfos.Last().PaymentTable.Rows.Add(dtRow)
End If
Next
Next
Return customerInfos
Same code with C# (hope no syntax errors occurred):
var customerTitlesAndIDs = contex.CustomerTable.Select(row => new
{ .ID = row.ID, .CustomerTitle = row.Title }).ToList();
var cutomerIdPayment = contex.CustomerPayments.Select(table => new
{
.ID = table.CustomerID,
.Range = table.PaymentsRange,
.Values = table.Values
}).ToList();
List<SCustomerInfo> customerInfos = new List<SCustomerInfo>;
foreach (var customer in customerTitlesAndIDs)
{
int cID = customer.ID;
customerInfos.Add(new SCustomerInfo(CreateCustomerTable(), cID, customer.CustomerTitle));
foreach (var cutomerPayments in cutomerIdPayment)
{
if (cutomerPayments.ID = cID)
{
object[] rangeValue = new object[1] {cutomerPayments.Range, cutomerPayments.Values};
DataRow dtRow = customerInfos.Last().PaymentTable.NewRow();
dtRow.ItemArray = rangeValue;
customerInfos.Last().PaymentTable.Rows.Add(dtRow);
}
}
}
SCustomerInfo represented by folowing Structure (code is simplified):
Public Structure SWindAltitude
Public PaymentTableAs DataTable
Public Title As String
Public ID As Integer
End Structure
Both C# and VB.NET solutions will be helpful.
Try something like this, utilizing navigation properties (you'll probably have to massage it as I don't know the exact makeup of your data structures):
var customerQuery = context.CustomerTable.Select( ct =>
new {
ct.ID,
ct.CustomerTitle,
// use nav property to get customer payments
CustomerPayments = ct.CustomerPayments.Select( cp =>
new {
Range = cp.Range,
Values = cp.Values } ) } );
return customerQuery.ToArray()
.Select( cq =>
{
var retVal = new SCustomerInfo( CreateCustomerTable(), cq.ID, cq.CustomerTitle );
foreach( var customerPayment in cq.CustomerPayments )
{
var dtRow = cq.PaymentTable.NewRow();
dtRow.ItemArray = new object[] { customerPayment.Range, customerPayment.Values };
retVal.PaymentTable.Rows.Add( dtRow );
}
return retVal;
} );
if i understand right in c# with linq it will be something like this
var customerInfos = customerTitlesAndIDs.Select((c)=>{
var ci = new SCustomerInfo(CreateCustomerTable(), c.ID, customer.CustomerTitle);
ci.PaymentTable = ci.PaymentTable.AsEnumerable().Union(
cutomerIdPayment.Where(j=>j.ID == c.ID)
.Select(j=>{
var dtRow = ci.PaymentTable.NewRow();
dtRow.ItemArray = new object[] {
customerPayment.Range,
customerPayment.Values
};
return dtRow;
})).CopyToDataTable();
return ci;
}).ToList();
I think you can use the Linq provided function Sequence.concat() as described here: http://msdn.microsoft.com/en-us/library/vstudio/bb386979(v=vs.100).aspx
In this question, Add a column to IEnumerable in C#, I got the following code:
var db = Database.Open("LOS");
var ie = db.Query(sqlAssignments);
// make a new ie2 that has an extra calculated field
var ie2 = processes.Select( e => new { e.ACCT, e.RefID, color = e.RefID + 9000000 });
var grid = new WebGrid(ie2.ToList(), rowsPerPage : 50, ajaxUpdateContainerId : "grid" );
The data correctly shows up, however the grid no longer sorts. It sorts fine if you pass ie, instead of ie2. It has the problem if I do the ToList() or not. Obviously there's some difference between ie and ie2. Here's the GetType for ie:
System.Collections.ObjectModel.ReadOnlyCollection`1[System.Object]
and for ie2:
System.Linq.Enumerable+WhereSelectEnumerableIterator`2[System.Object,<>f__AnonymousType0`10[System.Object,System.Object,System.Object,System.Object,System.Object,System.Object,System.Object,System.Object,System.Object,System.Object]]
What should I do to ie2 to make it work with WebGrid and sort correctly?
Try to create a type for ie2 instead of using an anonymous type, like:
var ie2 = processes.Select( e =>
new MyNewType { ACCT = e.ACCT, RefID = e.RefID, Color = e.RefID + 9000000 }
);
Where the new type would be:
class MyNewType {
public string ACCT { get; set }
public int RefID { get; set }
public int Color { get; set }
}