Alternate of Class Object while creating formatted List - c#

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.

Related

Linq to populate values of a class

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.

How to fetch entity records from CRM

I am very new to MS-CRM and I want to retreive all the details of the contact
var executeQuickFindRequest = new OrganizationRequest("ExecuteQuickFind");
executeQuickFindRequest.Parameters = new ParameterCollection();
var entities = new List<string> { "contact", "lead", "account" }; //specify search term
executeQuickFindRequest.Parameters.Add("SearchText", "maria");
//will cause serialisation exception if we don't convert to array
executeQuickFindRequest.Parameters.Add("EntityNames", entities.ToArray());
var executeQuickFindResponse = _orgService.Execute(executeQuickFindRequest);
var result = executeQuickFindResponse.Results;
The data here displayed contains display name's such as address_1_City,email_user
However I want to get there actual names like Address,Email etc etc.
Thanks
Just to extend what BlueSam has mentioned above.
EntityMetadata entityMetaData = retrieveEntityResponse.EntityMetadata;
for (int count = 0; count < entityMetaData.Attributes.ToList().Count; count++)
{
if (entityMetaData.Attributes.ToList()[count].DisplayName.LocalizedLabels.Count > 0)
{
string displayName = entityMetaData.Attributes.ToList()[count].DisplayName.LocalizedLabels[0].Label;
string logicalName = entityMetaData.Attributes.ToList()[count].LogicalName;
AttributeTypeCode dataType = (AttributeTypeCode)entityMetaData.Attributes.ToList()[count].AttributeType;
}
}
Above code will help you to get the display name, logical name and data type for each attribute in the entity. Similarly you can get other information as well from the entityMetaData object as per above code snippet.
As far as I know, you will need to pair it up with the attributes of the entities that are for that request. Here's a sample of how to retrieve an entity:
RetrieveEntityRequest retrieveBankAccountEntityRequest = new RetrieveEntityRequest
{
EntityFilters = EntityFilters.Entity,
LogicalName = entityName
};
RetrieveEntityResponse retrieveEntityResponse = (RetrieveEntityResponse)_serviceProxy.Execute(retrieveBankAccountEntityRequest);
You can do it easy as below
using (var service = new OrganizationService(CrmConnection.Parse("CRMConnectionString")))
{
var Res = service.Retrieve("sv_answer", new Guid("GUID Of Record"), new ColumnSet("ColumnName "));
}

Convert DataTable to LINQ Anonymous Type

I want a function which takes in a datatable & returns a List (object is not DataRow)
Eg. :
I know I can do this (but this requires column names to be known) :
// Datatable dt = Filled from a Database query & has 3 columns Code,Description & ShortCode
List<object> rtn = new List<object>();
var x = from vals in dt.Select()
select new
{
Code = vals["Code"],
Description = vals["Description"],
ShortCode = vals["ShortCode"],
};
rtn.AddRange(x)
return rtn;
What i want is a generic version so that i can pass in any datatable & it will generate based on column names in the datatable.
Since the property names are not known at compile time and you want to use the data for JSON serialization, you can use the following to create a list of dictionary. If you use Newtonsoft JSON, then the serialization takes care of converting the key value pairs in a JSON object format.
IEnumerable<Dictionary<string,object>> result = dt.Select().Select(x => x.ItemArray.Select((a, i) => new { Name = dt.Columns[i].ColumnName, Value = a })
.ToDictionary(a => a.Name, a => a.Value));
In order to dynamically create properties so as to treat different dataTables with different set of Columns, we can use the System.Dynamic.ExpandoObject. It basically implements, IDictionary <string,object>. The format, which can easily be converted to JSON.
int colCount = dt.Columns.Count;
foreach (DataRow dr in dt.Rows)
{
dynamic objExpando = new System.Dynamic.ExpandoObject();
var obj = objExpando as IDictionary<string, object>;
for (int i = 0; i < colCount; i++)
{
string key = dr.Table.Columns[i].ColumnName.ToString();
string val = dr[key].ToString();
obj[key] = val;
}
rtn.Add(obj);
}
String json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(rtn);
You can use the following generic function:-
private static List<T> ConvertDataTable<T>(DataTable dt)
{
List<T> data = newList<T>();
foreach (DataRowrow in dt.Rows)
{
Titem = GetItem<T>(row);
data.Add(item);
}
return data;
}
private static TGetItem<T>(DataRow dr)
{
Type temp = typeof(T);
T obj =Activator.CreateInstance<T>();
foreach (DataColumncolumn in dr.Table.Columns)
{
foreach (PropertyInfopro in temp.GetProperties())
{
if (pro.Name == column.ColumnName)
pro.SetValue(obj,dr[column.ColumnName], null);
else
continue;
}
}
return obj;
}
Please check my article, which has complete demonstration on how to use this generic method.
Here is the original question:
// Datatable dt = Filled from a Database query & has 3 columns Code,Description & ShortCode
List<object> rtn = new List<object>();
var x = from vals in dt.Select()
select new
{
Code = vals["Code"],
Description = vals["Description"],
ShortCode = vals["ShortCode"],
};
rtn.AddRange(x)
return rtn;
Just replace with
List<object> rtn = JsonConvert.DeserializeObject<List<object>>(JsonConvert.SerializeObject(dt));
You will have the provide the anonymous object as a parameter and use json/xml serialization:
protected static List<T> ToAnonymousCollection<T>(DataTable dt, T anonymousObject)
{
List<DataColumn> dataColumns = dt.Columns.OfType<DataColumn>().ToList();
return dt.Rows.OfType<DataRow>().Select(dr =>
{
Dictionary<string, object> dict = new Dictionary<string, object>();
dataColumns.Each(dc => dict.Add(dc.ColumnName, dr[dc]));
return JsonConvert.DeserializeAnonymousType(JsonConvert.SerializeObject(dict), anonymousObject);
}).ToList();
}
Usage:
var anonymousCollection = ToAnonymousCollection(dt, new { Code = [ColumnTypeValue, eg. 0], Description = [ColumnTypeValue, eg. string.Empty], ShortCode = Code=[ColumnTypeValue, eg. 0] })

epplus using LoadFromCollection with anonymous types

I have a IEnumerable<object> dataSource which contains a collection anonymous types. The actual structure of the anonymous type won't be known at design time, so I'm trying to find a generic solution that can handle any anonymous type.
How can I load them into epplus to create a spreadsheet? I have a worksheet called ws and I tried:
ws.Cells["A1"].LoadFromCollection(dataSource, true);
However when that runs it outputs all of the anonymous type's properties into a single cell:
{ Id = 10000, Title = This is a test }
I've tried passing in MemberInfo using:
var members = dataSource.First().GetType().GetMembers();
ws.Cells["A1"].LoadFromCollection(this._dataSource, true,
TableStyles.Medium1, BindingFlags.Public, members);
But that throws an exception:
Supplied properties in parameter Properties must be of the same type as T
Any suggestions on how I can create a spreadsheet using anonymous types in c#?
I have tested
using (var excel = new OfficeOpenXml.ExcelPackage())
{
var sheet = excel.Workbook.Worksheets.Add("Test");
sheet.Cells["A1"].LoadFromCollection(dataSource, true);
excel.SaveAs(new FileInfo(#"C:\Temp\Test.xlsx"));
}
with this sample data:
var dataSource = Enumerable.Range(1, 100).Select(i => new{ ID=i, Title="Title " + i });
It works fine. It creates two columns with the correct headers and 100 rows.
But you should use anonymous types only if you know the structure at compile time.
You could use a DataTable and LoadFromDataTable instead. Since i don't know how you create the anonymous type i show you just a small sample:
DataTable dataSource = new DataTable();
dataSource.Columns.Add("Id"); // default type is string
dataSource.Columns.Add("Title");
// add other columns
dataSource.Rows.Add("1", "Title1");
// add other rows
using (var excel = new OfficeOpenXml.ExcelPackage())
{
var sheet = excel.Workbook.Worksheets.Add("Test");
sheet.Cells["A1"].LoadFromDataTable(dataSource, true);
excel.SaveAs(new FileInfo(#"C:\Temp\Test.xlsx"));
}
You could group the anonymous types to make it easier for exporting with dataTables. The bug "Supplied properties in parameter Properties must be of the same type as T" is still there and a workaround is using DataTables.
// Imagine list is your main datasource
IEnumerable<object> list = Enumerable.Empty<object>(); // Data Source of <object>
// Added anon types at runtime added to the object list
var anonTypesOne = new object[]
{
new { GuidID = Guid.NewGuid(), StringProperty = "the string property" },
new { IntegerID = 1, IntegerProperty = 99 }
};
var anonTypesTwo = new object[]
{
new { StringID = "1", BooleanProperty = true, NumberProperty = 3, StringProperty = "Four" },
new { GuidID = Guid.NewGuid(), NumberThree = 3 },
new { GuidID = Guid.NewGuid(), NumberThree = 3 },
new { GuidID = Guid.NewGuid(), NumberThree = 3 }
};
list = list.Concat(anonTypesOne).Concat(anonTypesTwo);
// Grouping works on anon types so we can group the export into their own tables
var groupings = list.GroupBy(i => i.GetType());
using(var package = new ExcelPackage(new FileInfo("C:\\Temp\\Anon.xlsx")))
{
var ws = package.Workbook.Worksheets.Add("Anonymous Types");
// add each "anon type matched grouping"
foreach(var grouping in groupings)
{
var isNew = ws.Dimension == null; // the sheet is empty if Dimension is null.
var row = 0;
if(isNew)
{
row = 1; // start from the first row
}
else
{
// otherwise there are tables already, start from the bottom
row = ws.Dimension.End.Row;
}
// because of EPP inheritance bug of T, we can just use dataTable
DataTable dt = new DataTable(grouping.Key.Name);
var properties = grouping.Key.GetProperties(); // Get anon type Properties
foreach(var property in properties)
{
dt.Columns.Add(property.Name);
}
foreach(var item in grouping.ToList())
{
var dataRow = dt.NewRow();
foreach(var p in properties) // populate a single row
{
dataRow[p.Name] = p.GetValue(item); // item is anon object instance
}
dt.Rows.Add(dataRow);
}
if(isNew) // load into the top most left cell of the worksheet
ws.Cells[1, 1].LoadFromDataTable(dt, PrintHeaders: true);
else // load from the dimension of current items + 1 row for spacing
ws.Cells[ws.Dimension.End.Row + 1, 1].LoadFromDataTable(dt, PrintHeaders: true);
ws.InsertRow(ws.Dimension.End.Row + 2, 5); // Insert some padding between each group
}
package.Save();
}
I was, this thread is older, but I'm looking for the same problem.
With the following code (VB) I have success.
Carsten
Dim targetFile = New IO.FileInfo(sFN)
Dim dataSource = Enumerable.Range(0, 1).Select(Function(i) New With {.ID = 1000, .Titel = "This is a test "}).ToList
Using epp = New OfficeOpenXml.ExcelPackage(targetFile)
Dim ws = epp.Workbook.Worksheets.Add("lst_Anonymous")
ws.Cells(1, 1).LoadFromCollection(dataSource, True,
OfficeOpenXml.Table.TableStyles.Medium1,
Reflection.BindingFlags.Public,
dataSource.GetType.GetGenericArguments()(0).GetProperties)
epp.Save()
End Using

Get datatable and filling model from it

In my project i have a fill method.
public IList<MyModel> Fill(DataTable dt)
{
IList<MyModel> IProperty = new List<MyModel>();
for (int i = 0; i < dt.Rows.Count; i++)
{
MyModel Property = new MyModel
{
Name= dt.Rows[i]["Name"].ToString(),
Surname = dt.Rows[i]["Surname"].ToString(),
Age = dt.Rows[i]["Age"].ToString(),
};
IProperty.Add(Property);
}
return IProperty;
}
It fill my model from datatable. But i must write this fill method for all model. I dont want to write this method all the time. I need a solution for this. I'm open to any kind of proposal
Not:I dont want to use Entity framework or other ORM frameworks.
If you can make sure the field names and properties of the object with the same name, try this:
public IEnumerable<T> Fill<T>(DataTable dt)
where T : new()
{
return dt.AsEnumerable().Select(row =>
{
var obj = new T();
var properties =
from p in obj.GetType().GetProperties()
join c in dt.Columns.Cast<DataColumn>() on p.Name equals c.ColumnName
select new {p, c};
foreach (var item in properties)
item.p.SetValue(obj, row[item.c]);
return obj;
});
}

Categories

Resources