How to set the column order of DTO properties programatically - c#

I am having simple DTO class. I would like to dynamically set the column order of this dto properties when the results are stored into excel.
Public class Student
{
public int Id {get;set;}
public string FirstName {get;set;}
public string LastName {get;set;}
}
I know there is a way using DataAnnotation Column Order Attribute on each property inside DTO. But is there a way to handle this using code to set the column order of DTO.
I am using simple web application and added System.ComponentModel.DataAnnotation Reference.
If there is a work around without using DataAnnotation to set the column order using code that will be great

What about using a static array inside your class or in a different class which list all columns in the order you want, and while saving to excel you loop through this array first to get columns in the correct order.
Something like that:
public class Student
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public List<string> OrderedProperties => new List<string> { "LastName", "FirstName", "Id" };
}
public class DataAccess
{
public void SaveStudentToExcel()
{
var student = new Student(); // instead of new this should be your object filled with real data.
foreach (var propName in student.OrderedProperties)
{
var val = student.GetType().GetProperty(propName).GetValue(student, null);
// new cell in excel => with val and propName then save
}
}
}

Related

How to use AutoMapper without Entity Framework?

I am learning how to use AutoMapper. First thing first, I don't use Entity Framework to read my data.
Hence, in my case I have to do manual mapping for each of the properties of my response model.
Below code may help you get more insight of this:
Response model:
public class TotalLossResults
{
public string N_CLAIM_NUMBER { get; set; }
public string N_CLAIM_ID { get; set; }
}
MapperClass:
public class TLResultsMapper : Profile
{
private TotalLossResults tlResultsObj = new TotalLossResults();
public TLResultsMapper()
{
IMappingExpression<DataRow, TotalLossResults> mappingExpression = CreateMap<DataRow, TotalLossResults>();
foreach (var prop in tlResultsObj.GetType().GetProperties())
{
mappingExpression.ForMember(prop.Name, y => y.MapFrom(s => s[prop.Name]));
}
}
}
Note: in the mapper class I used for each to get rid of the mappingExpression.ForMember statement for each property. But this works only when the property name is the same as of the column name (entity name for example) of the result which I get from the database.
I am looking out for some option where I can take similar approach to map the data values to my response model properties when the property's names are not matching with the column names.
I tried doing something like this:
I created another class which has the properties with different names:
public class TLResultsDifferentNames
{
public string N_CLAIM_NUMBER { get; set; }
public string N_CLAIM_ID { get; set; }
}
and a mapper implementation like this:
private TLResultsDifferentNames tlResultsObj = new TLResultsDifferentNames ();
private TotalLossResults tlResultsColObj = new TotalLossResults ();*
for (int i = 0, j = 0; i<tlResultsObj.GetType().GetProperties().Length - 1 && j<tlResultsColObj.GetType().GetProperties().Length - 1; i++, j++)
{
mappingExpression.ForMember(tlResultsObj.GetType().GetProperties()[i].Name, y => y.MapFrom(s => s[tlResultsColObj.GetType().GetProperties()[j].Name]));
}
But this doesn't work. It binds the last column values to all the model properties.
Any help/suggestion to achieve the mapping without using the manual way of mapping would be very helpful.
I could find something really interesting in Auto Mapper today. Which is Attribute Mapping and using that i need not to worry about any sort of manual/dynamical mapping for my models.
Below is the code which works perfectly now for all the properties:
Ex1: here all the properties' names are same
[AutoMap(typeof(object))] //this takes our Source class name
public class TotalLossResults
{
public string N_CLAIM_NUMBER { get; set; }
public string N_CLAIM_ID { get; set; }
}
Ex2: here we got different properties
[AutoMap(typeof(TotalLossResults))] //this takes our Source class name
public class TLResultsDifferentNames
{
[SourceMember(nameof(TotalLossResults.N_CLAIM_NUMBER))]
public string claimNumberOfJack { get; set; }
public string claimIDofJack { get; set; }
}
For mapping configuration we gonna use the below code:
var config1 = new MapperConfiguration(cfg =>
cfg.AddMaps(typeof(TotalLossResults)));
var mapper = new Mapper(config1);
var response = mapper.Map<TotalLossResults>(sourceObject);
Note: Its better to have the configs created in App Start.

how to add new type to an existing class or object in asp.net mvc

i want to add a new type to an existing class(object?) that fetch from database table (with entity framework class) in Microsoft MVC.
i.e:
my person class {f_name, l_name}
how can i add new type to this objects when i loop throw it?
like:
// Person class stracture is:
public Person()
{
public string f_name { get; set; }
public string l_name { get; set; }
}
i want to add 'age' to it without add this to model
var all_persons = db.Person.toList();
for (var item in all_person)
{
item.age = some_value;
}
return View(all_persons);
Add a [NotMapped] (assuming you dont want this property to be mapped to database) in your Person class:
[NotMapped]
public int Age {get; set;}
Or create a view model instead of using EF model directly
Example using Entity Framework :
If you are using code-first approach then [NotMapped] will work fine for you.
But if you are using model-first approach then it will not work because if you are going to update your model its going to be updated according to .tt template of model and create a class with only properties in tables.
So, what now ? here comes the concept of partial class.
model generated from EF :
namespace EF.Model
{
public partial class Person
{
public string f_name { get; set; }
public string l_name { get; set; }
}
}
So to add additional properties that you don't want EF to map while CRUD operations. Add a new partial class in the same project with same class name and same namespace as of EF model
namespace EF.Model
{
public partial class Person
{
public string fullName { get; set; }
public int age { get; set; }
}
}
So now you can do like this.
var all_persons = db.Person.toList();
for (var item in all_person)
{
item.age = some_value;
item.fullName = item.f_name + item.l_name;
}
return View(all_persons);
I hope this would give you a better understanding. You should read about partial classes.
https://www.dotnetperls.com/partial
You can add the new property in a linq Select as follows:
void AddNewField(int number)
{
var all_persons = new db.Person.Select(x => new { x.f_name, x.l_name, age = number });
return View(all_persons);
}
This will save you having to actually add the new field to the model.

Remove columns from list object out of a class c#

I need the possiblity to create Code in C# like this
public class SummaryA
{
public string name { get; set; }
public string surename { get: set; }
public int age { get; set;}
}
now I create an list object from the class SummaryA
List<SummaryA> list1= new List<SummaryA>();
yet I need the possibility to remove the column age from the list Summary, anyone have ideas?
I need this for some more columns, so I wish the list was dynamically or some things else.
sry for my bad english.
To completely remove the column you really need another class to store the data in, for example:
public class AgelessSummaryA
{
public string name { get; set; }
public string surename { get: set; }
}
And now you can project the first list into a new list of this class with Linq and Select:
List<AgelessSummaryA> agelessSummaries = ageSummaries
.Select(s => new AgelessSummaryA
{
name = s.name,
surename = s.surename
})
.ToList();
To use it for in a grid or for some display i guess, then you can use anonymous types where you can shape the data the way you like:
var projectedList = (from l in list1
select new
{
name = l.name,
surename = l.surename
}).ToList();

Composite indexes with RavenDB

I'm trying to create a composite index using RavenDB. Basically, I have 2 models that I need "joined" and able to perform searches on the result.
Here's an example of my models:
Model 1:
public class UserProfile {
public string ProfileId { get; set }
public string FirstName { get; set }
public string LastName { get; set }
public string EmailAddress { get; set }
}
Model 2:
public class UserProjects {
public string UserProjectId { get; set }
public List<Project> Projects { get; set }
}
Here's the Project Model, in case you're wondering:
public class Project {
public string ProjectId { get; set; }
public string Name { get; set; }
}
The UserProjectId property is as follows: users/<Email Address>/projects.
I was able to create an index that returns all the fields, but I'm not able to search on certain fields.
Here's my index:
public class ProfileProjectIndex : AbstractIndexCreationTask<UserProfile> {
Map = profiles =>
from profile in profiles
select new {
profile.ProfileId,
profile.FirstName,
profile.LastName,
profile.EmailAddress
};
TransformResults = (db, results) =>
from result in results
let project = db.Load<UserProjects>("users/" + profile.EmailAddress + "/projects")
select new {
result.ProfileId,
result.EmailAddress,
result.FirstName,
result.LastName,
project.UserProjectId,
project.Projects
};
}
Now this index, when querying Raven from the web interface, returns the complete list of data I could want, but I need to be able to filter the results based on some values included in the UserProjects.Projects list, for example:
return all user profiles with associated projects when Project.Projects.Contains(x => x.ProjectId == "projects/1234")
Any RavenDB gurus can enlighten me? Oh, and I'm using RavenDB 2.5.
You are probably looking at multi map indexes, see:
http://ravendb.net/docs/article-page/3.0/csharp/indexes/multi-map-indexes

Change the order of asp:GridView *autogenerated* columns

First let me say that I've seen similar questions on StackOverflow, but none that I've seen deal specifically with auto-generated columns.
I have a asp:GridView that I am binding to an IEnumerable<Data>, where Data can vary depending on runtime input. However, each Data class shares a couple base properties:
public class BaseData
{
public int ID { get; set; }
public string Name { get; set; }
}
public class AddressData : BaseData
{
public string Street1 { get; set; }
public string Street2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; };
}
public class ContactData : BaseData
{
public string Phone { get; set; }
public DateTime LastUpdated { get; set; }
// tons more public properties...
}
// More classes with lots of different public properties...
These different classes are populated by a database query, so I want to auto-generate columns when I place the data in the GridView because of the large number of different fields. However, I want to display the columns that are in the shared base class first. If I just assign the IEnumerable<Data> to the GridView datasource, the base classes properties are added last to the GridView's columns. I tried remedying the situation like this:
// Callback after getting data from database
public void SetGridView<Data>(IEnumerable<Data> rows) where Data : BaseData
{
// Make sure these columns show up first
BoundField ID = new BoundField() { HeaderText = "ID", DataField = "ID" };
BoundField Name = new BoundField() { HeaderText = "Name", DataField = "Name" };
myGridView.Columns.Clear();
myGridView.Columns.Add(ID);
myGridView.Columns.Add(Name);
myGridView.AutoGenerateColumns = true;
myGridView.DataSource = rows;
myGridView.DataBind();
}
However, this just duplicates the columns at the beginning and end, so the header looks like this:
ID Name Street1 Street2 City State ZipCode ID Name
So is there a way for me to move the columns that I know will be there (base class) to the beginning of the GridView's columns while still having the convenience of auto-generating all the other columns?
Since you are forced to use auto-generated columns, I'd just create an intermediate DataTable to bind the GridView to. In that DataTable object, you can add your columns in the order you prefer. The GridView should then bind in that same order.
Edit:
Modify BaseData, add the following:
private DataTable dataForDisplay;
// This would be overridden by all child classes, adding their columns in the order you want
public virtual DataTable GetDataForDisplay()
{
dataForDisplay = new DataTable();
dataForDisplay.Columns.Add("ID");
dataForDisplay.Columns.Add("Name");
// If you want to change the order, just don't call the base.GetDataForDisplay()
dataForDisplay.Rows.AddRange(this.ID, this.Name);
return dataForDisplay;
}
Then all of the other child classes will override GetDataForDisplay().

Categories

Resources