Creating Complex Automapper - c#

I am trying to use the automapper to map my Database table output to my class object. But the table has 3 rows that are all belong to single employee data which needs to be assigned to a single class object. How we can we create mapper ? Is it possible to create mapper with this table data ?
How can I write Autommapper to populate the class EmployeeDetails
public class EmployeeDetails
{
public string EmpNo { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
public List<Phone> Phone { get; set; }
}
public class Address
{
public string Address_1 { get; set; }
public string City { get; set; }
}
public class Phone
{
public string PhoneType { get; set; }
public string PhoneNo { get; set; }
}
Datatype EmpNo Name Address_1 City PhoneType PhoneNo
Name 1234 Test Test addr Testcity Null Null
Phone 1234 Null Null Null Mobile 123456
Phone 1234 Null Null Null Work 789546
public IEnumerable< EmployeeDetails > GetEmployeeDetails()
{
return ExecuteEmpReader< EmployeeDetails>().ToList();
}
private IEnumerable<T> ExecuteEmpReader <T>()
{
DataTable dt=new Datatable();
//Assume the dt will be loaded as per the above table.
foreach (DataRow item in dt.Rows)
{
yield return _mapper.Map<T>(item)
}
}

I don't believe there is a way to do what you want using solely Automapper. Specifically because of the merging of rows into one. This link shows how you can at least unflatten your object to your desired object structure, but then you would need to write the logic to merge the employees addresses and phone numbers yourself.
http://martinburrows.net/blog/2016/01/18/automatic-unflattening-with-automapper
On the contrary to make your resulting code easier to maintain in future. I would recommend creating some views of your Employee Object, one for Employee, one for Address, and one for Phone. Then you can use EF to map your views straight to your objects.

Related

c# How to add data into existing collection item

I am trying to add data to an existing List item. Currently I have two different collections. This is a subset of what I am working with and what I am trying to achieve.
List<Products> products = new List<Products>();
List<Fitment> fitment = new List<Fitment>();
class Fitment
{
public string Sku { get; set; }
public string Model { get; set; }
public string Years { get; set; }
}
class Products
{
public string Sku { get; set; }
public string Price { get; set; }
public string Vendor { get; set; }
}
What I need to do is match the SKU from the fitment list and add it to the item with the same SKU in the products list. One product can have several fitments (for example, a car seat that is used in multiple vehicles). The products list has 100k+ items and the fitment list has 400k+ items so I am looking for the fastest method to do this. I have tried several methods that time extremely long to process. What is the fastest way?
I solved my problem. I switched the Product to a Dictionary and used this to add the fitment data to the product data
productFitment.ForEach(fitment =>
{
if (dicProducts.ContainsKey(fitment.Sku))
dicProducts[fitment.Sku].ProductFitment.Add(fitment);
else
Console.WriteLine(fitment.Sku);
});

C# datatable Entity Framework

I have two objects people and house, and I want to show the table people in a datagridview, but in the field House, the value shown is Program.Model.House; I want to show the street name instead, how I can do it? (I'm using Entity Framework and the data source of data grid view I use context.tolist())
public class People
{
public string Name { get; set; }
public House House { get; set; }
}
public class House
{
public string Street { get; set; }
public int Number { get; set; }
}
Override ToString() in House class. Like that :
public override string ToString(){ return $"Street: {Street}"; }
You wanted to show data like Name and Street Name
For Name You can use Model.Name
For Street Name you can use Model.House.Street
For Example
#foreach(var item in Model)
{
<td> #Model.Name</td>
<td> #Model.House.Street</td>
}
May this help you
Simply create a new object for grid view with a street name.
List<object> peopleData=new List<object>();
peopleData.Add(new{ ppl.Name,ppl.House.Street });
grdPeople.DataSource = peopleData;```

How to convert Model class object to datatable

I am new to c# ,I want to convert a model class object to DataTable in Web API.
Model Class
public class Employee_Master_Model
{
public string UserType { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string MiddleName { get; set; }
public string Mobile { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public bool IsActive { get; set; }
public int EmployeeId { get; set; }
}
Controller:
public async Task<IActionResult> CreateEmployee([FromBody] Employee_Master_Model employee_Master_Model)
{
try
{
// Need to convert the object (employee_Master_Model) to DataTable
}
catch (Exception ex)
{
throw ex;
}
}
trying it for hours can't get it done .Can anyone help me to fix this .
By the following code you can dynamically create the datatable columns:
PropertyDescriptorCollection props =
TypeDescriptor.GetProperties(typeof(Employee_Master_Model));
DataTable dt = new DataTable();
foreach (PropertyDescriptor p in props)
dt.Columns.Add(p.Name, p.PropertyType);
The rest is just copying entity fields values to datatable columns.
Why can't you just create a datatable and fill it with the model data value like
DataTable dt = new DataTable();
DataColumn c = new DataColumn("FirstName");
dt.Columns.Add(c);
DataRow r = dt.NewRow();
r["FirstName"] = model.FirstName; // model is an instance of Employee_Master_Model
You have a number of issues in your code.
First, EmployeeId has no business being part of your create model. Let the database generate the id for you. I suspect you use Employee_Master_Model for both create and update. If that is the case I would suggest you stop doing that, create a separate model for create and remove the properties you don't need.
Second, do not return a DataTable from your API. A common approach is to return the generated id of the created entity and nothing more. If you really need to get all the data then you can create a GET endpoint, pass it the id you just received and that will give you the data.
Third, since you are using WebAPi, learn to use models and learn to use DTOs ( Data Transfer Objects ). Those are commonly used for returning data. Datatables are part pf a database implementation, you don't want that exposed via the API.

Entity Framework inserting new rows instead of updating them

I have a problem when I am updating data to database. When I want to update data, Entitiy Framework adds new rows to tables that can have multiple rows (tables that have foreign key).
Database model:
When I update Phone/Contact or Tags entity, Entity Framework automatically adds new row instead of updating it
Here is code that I used:
public string UpdateContact(Contact contact)
{
if (contact != null)
{
int id = Convert.ToInt32(contact.id);
Contact Updatecontact = db.Contacts.Where(a => a.id == id).FirstOrDefault();
Updatecontact.firstname = contact.firstname;
Updatecontact.lastname = contact.lastname;
Updatecontact.address = contact.address;
Updatecontact.bookmarked = contact.bookmarked;
Updatecontact.city = contact.city;
Updatecontact.notes = contact.notes;
Updatecontact.Emails1 = contact.Emails1;
Updatecontact.Phones1 = contact.Phones1;
Updatecontact.Tags1 = contact.Tags1;
db.SaveChanges();
return "Contact Updated";
}
else
{
return "Invalid Record";
}
}
EDIT:
Here is EF Model code:
Contact:
public partial class Contact
{
public Contact()
{
this.Emails1 = new HashSet<Email>();
this.Phones1 = new HashSet<Phone>();
this.Tags1 = new HashSet<Tag>();
}
public int id { get; set; }
public string firstname { get; set; }
public string lastname { get; set; }
public string address { get; set; }
public string city { get; set; }
public Nullable<byte> bookmarked { get; set; }
public string notes { get; set; }
public virtual ICollection<Email> Emails1 { get; set; }
public virtual ICollection<Phone> Phones1 { get; set; }
public virtual ICollection<Tag> Tags1 { get; set; }
}
Emails/Tags and Phone have same model (with different name for value)
public partial class Email
{
public int id { get; set; }
public int id_contact { get; set; }
public string email1 { get; set; }
public virtual Contact Contact1 { get; set; }
}
Update properties rather than set new objects.
Updatecontact.Emails1.email1 = contact.Emails1.email1;
Updatecontact.Phones1.number = contact.Phones1.number;
Updatecontact.Tags1.tag1 = contact.Tags1.tag1;
Edit: seems that your contact model has lists of emails, phones and tags. If this is so, then simple assignment won't work. Instead, when sent from the client, you have to find one-by-one and update:
foreach ( var email in contact.Emails1 )
{
// first make sure the object is retrieved from the database
var updateemail = Updatecontact.Emails1.FirstOrDefault( e => e.id == email.id );
// then update its properties
updateemail.email1 = email.email1;
}
// do the same for phones and tags
It's doing that because you're setting the different HashSet values to the values of a completely different collection, namely from what you call contact in that method. In order for you to properly do an update, you're going to have to loop through the emails, phones, and tags to check if those need to be added/updated/deleted on the actual object that you're trying to update.
First, why do you have to search for the contact if you are already receiving it by parameter? That makes me think that you are creating a new one because you are in a different context, if so, then it creates a new record because you have 2 different object in 2 different context.
Try using just one object in the same context to update, EF should mark the object to modification by itself, if not then try making sure before saving that your object has EntityState.Modified.

How do I update the value of a complex object within another object?

Given the following two classes, which are representing tables in a database, I want to set the statustype of MyClass to one of the two predefined values that are in the StatusType DB.
public class MyClass
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
[DataType(DataType.MultilineText)]
public string Description { get; set; }
public virtual StatusType StatusType { get; set; }
}
public class StatusType
{
public int Id { get; set; }
public virtual ICollection<MyClass> MyClasses{ get; set; }
DataType(DataType.MultilineText)]
public string Description { get; set; }
}
There is a third table (MyClass_StatusType) that is not represented by an entity that acts as a many to one intermediary.
My code:
MyClass mc = new MyClass();
mc.Description = "Description";
mc.StatusType.Id = 3;
db.MyClasses.Add(mc);
var id = db.SaveChanges();
There is a record in my StatusType with an ID of 3. When I run this code I get a null reference exception on the StatusType.
What is the correct way to set this value in MyClass?
You get the exception because of the access to StatusType in this line
mc.StatusType.Id = 3;
mc is a new object and has no StatusType defined.
1) The best way to correct this is to use the FK field StatusTypeId
mc.StatusTypeId = 3;
2) But if you can't use this field the other solution is the following:
You should instead of setting the Id (of an non existing StatusType) set it to the existing type. This makes a extra roundtrip to the DB to get the StatusType object.
var statusType = MyMethodToGetExistingStatusType(3);
mc.StatusType = statusType;
I don't know how you can get your instance of your Type but in the method MyMethodToGetExistingStatusType() you can handle this.
I hope this helps you?
You are missing your FK in the MyClass class. If you add
Public int StatusTypeId {get;set;}
This maps a FK for your entity. Currently you only have a navigation property.
Then rather than doing
mc.StatusType.Id = 3
You just do
mc.StatusTypeId = 3
This will save you from having to select from the StatusType table. Meaning a lot less code and one less trip to your SQL server.

Categories

Resources