C# map two complex objects - c#

I have four classes :
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public List<Product> Product { get; set; }
}
public class Product
{
public int ProductNumber { get; set; }
public string ProductColor { get; set; }
}
///////////////////////////////////////////////
public class Customer_
{
public string FirstName { get; set; }
public string LastName { get; set; }
public List<Article> Article { get; set; }
}
public class Article
{
public int ArticleNumber { get; set; }
public string ArticleColor { get; set; }
}
And one instance :
var Cus = new List<Customer>
{
new Customer()
{
FirstName = "FirstName1",
LastName = "LastName1",
Product = new List<Product>
{
new Product()
{
ProductColor = "ProductColor1",
ProductNumber = 11
}
}
},
new Customer()
{
FirstName = "FirstName2",
LastName = "LastName2",
Product = new List<Product>
{
new Product()
{
ProductColor = "ProductColor2",
ProductNumber = 12
}
}
}
};
I want to create a new object List<Customer_> with the value of my instance Cus. For example Customer.FirstName = Customer_.FirstName, Customer.Product.ProductColor = Customer_.Article.ArticleColor etc
What is the best way to do this easily, could one use a Dictionary?

Mapping can be accomplished through the use of an Interface.
Define an interface(s) which provide a mapping of logically named properties such as the common color properties you mention:
// Some entities have different named properties but can be joined
// using those properties. This interface shows a common color which
// when implemented will route the processing to a common shared property
// which reports and sets the associated color.
public interface IDefinedColor
{
string Color { get; set; }
}
If you have to create partial classes for Product and Article and have them adhere to said interfaces. Hint if using an entity mapper such as EF this is a great way to do such maping using partials. Implement implement the interface and hook up the commonality:
// Holds the common properties for future processing.
public partial class Product : IDefinedColor
{
public string Color
{
get { return ProductColor; }
set { ProductColor = value; }
}
}
Then work off of the IDefinedColor mapped implementations as needed.
By using interfaces one is letting all future developers know of the contract which specifies a business logic equality in the properties and it is not hidden in other joining classes.

You could create a mapper extension class
public static class MapperExtension
{
public Customer_ Convert(this Customer customer)
{
return new Customer_()
{
FirstName = customer.FirstName,
LastName = customer.LastName,
Article = customer.Product.Convert()
};
}
public static List<Article> Convert(this List<Product> products)
{
return products.Select(x=> new Article(){
ArticleNumber = x.ProductNumber,
ArticleColor = x.ProductColor
};
}
}
make sure you reference the proper namespace where you place the extension class.
Call the code like this
Where customers is a List filled from your code
List<Customer_> convertedCustomers_ = customers.Select(x=> x.Convert()).ToList();

It depends on the relationhip between those components but I would simply add constructor to Customer_ that accepts a Customer object. And then you invoke that do perform the conversion. e.g.
public class Article
{
public Article(Product source)
{
this.ArticleNumber = source.ProductNumber;
this.ArticleColor = source.ProductColor;
}
}
public class Customer_
{
public Customer_(Customer source)
{
this.FirstName = source.FirstName;
this.LastName = source.LastName;
this.Article = source.Product.Select(o => new Article(o)).ToList()
}
...
}
//and finally to convert the list you can do something like
//initial list
var Cus = new List<Customer>() { ... etc. }
/converted list
var Cus_ = Cus.Select(o => new Cusomter_(o)).ToList();
Edit: I see from your comment above that you actually have 100 properties to map. I can see this is a pain. But if you have complex transformations like Product to Article then I would still go the manual route as above so you can be completely clear about what is going on. Alternatively you could look to use inheritance to redesign your objects with common base classes or interfaces, that would probably make mapping easier.

Related

DynamoDB - How to implement Optimistic Locking using ServiceStack.Aws

Currently, I am using ServiceStack.Aws v5.9.0 to communicate with DynamoDB. I have used PutItem for both creating and updating an item without anticipating data loss in case of concurrency handling.
public class Customer
{
[HashKey]
public int CustomerId { get; set; }
[AutoIncrement]
public int SubId { get; set; }
public string CustomerType { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
...//and hundreds of fields here
}
public class CustomerDynamo
{
private readonly IPocoDynamo db;
//Constructor
public CustomerDynamo()
{
var dynamoClient = new AmazonDynamoDBClient(_region);
var entityType = typeof(Customer);
var tableName = entityType.Name;
entityType.AddAttributes(new AliasAttribute(name: tableName));
db = new PocoDynamo(dynamoClient) { ConsistentRead = true }.RegisterTable(tableType: entityType);
}
public Customer Update(Customer customer)
{
customer.ModifiedDate = DateTime.UtcNow;
db.PutItem(customer);
return customer;
}
}
The above Update method is called in every service/async task that needs to update the data of the customer.
Refer to this article of AWS I decided to implement the Optimistic Locking to save my life from the issue of concurrency requests.
https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBContext.VersionSupport.html
Assume that the VersionNumber will be the key for Optimistic Locking. So I added the VersionNumber into the Customer model.
public class Customer
{
[HashKey]
public int CustomerId { get; set; }
[AutoIncrement]
public int SubId { get; set; }
public string CustomerType { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
...//and hundreds of fields here
[DynamoDBVersion]
public int? VersionNumber { get; set; }
}
The result is VersionNumber not updated while it should be automatically incremented. I think it is just because the PutItem will override the whole existing item. Is this correct?
I think I need to change from PutItem to UpdateItem in the Update method. The question is how can I generate the expression dynamically to be used with the UpdateItem?
Thanks in advance for any help!
Updates:
Thanks #mythz for the useful information about DynamoDBVersion attribute. Then I tried to remove the DynamoDBVersion and using the UpdateExpression of PocoDynamo as below
public Customer Update(Customer customer)
{
customer.ModifiedDate = DateTime.UtcNow;
var expression = db.UpdateExpression<Customer>(customer.CustomerId).Set(() => customer);
expression.ExpressionAttributeNames = new Dictionary<string, string>()
{
{ "#Version", "VersionNumber" }
};
expression.ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
{
{ ":incr", new AttributeValue { N = "1" } },
{ ":zero", new AttributeValue { N = "0" } }
};
expression.UpdateExpression = "SET #Version = if_not_exists(#Version, :zero) + :incr";
if (customer.VersionNumber.HasValue)
{
expression.Condition(c => c.VersionNumber == customer.VersionNumber);
}
var success = db.UpdateItem(expression);
}
But the changes are not saved except the VersionNumber
The [DynamoDBVersion] is an AWS Object Persistence Model attribute for usage with AWS's DynamoDBContext not for PocoDynamo. i.e. the only [DynamoDB*] attributes PocoDynamo utilizes are [DynamoDBHashKey] and [DynamoDBRangeKey] all other [DynamoDB*] attributes are intended for AWS's Object Persistence Model libraries.
When needed you can access AWS's IAmazonDynamoDB with:
var db = new PocoDynamo(awsDb);
var awsDb = db.DynamoDb;
Here are docs on PocoDynamo's UpdateItem APIs that may be relevant.

Mapster - How to do ignore mapping for null properties

I'm using Mapster to map Dto instances to Model objects.
The Dtos are sent by a Javascript client, sending only the properties updated.
I would like to ignore null values, and have Mapster leave the model instance unchanged for this properties.
A simplified example to better explain the scenario:
// My .Net Dto class, used for client/server communication.
public class PersonDto
{
public string Id { get; set; }
public string Name { get; set; }
public string Family { get; set; }
}
// My Model class. Let's assume is the same data as per the Dto.
public class Person
{
public string Id { get; set; }
public string Name { get; set; }
public string Family { get; set; }
}
public void Update()
{
var existingPerson = new Person
{
Id = "A",
Name = "Ned",
Family = "Stark"
};
var patchDataSentFromClient = new PersonDto
{
Id = "A",
Name = "Rob"
};
patchDataSentFromClient.Adapt(existingPerson);
// Here existingPerson.Family should be "Stark", but it gets emptied out.
// the mapping should be equivalent to:
// if (patchDataSentFromClient.Family != null) existingPerson.Family = patchDataSentFromClient.Family;
}
Edit: the point is I don't want to write down the mapping condition for each of the thousands of properties in my Dtos. I want Mapster to Automap all string properties by name, but keep the "patch-like" logic of ignoring null values.
You can use IgnoreNullValues.

what's an elegant method to transfer/cast a poco of 1 type to a poco of another type - different namespace but same name and fields?

Let's say you have a Domain layer which returns a User object:
public class User
{
public string FirstName{get;set;}
public string LastName{get;set;}
}
Let's say you have an identical class defined in your service layer. What's an elegant method to easily transfer/cast the Domain User object into a service User object?
"Elegant" is subjective. I might just write an extension that converts one to the other.
public static class MappingExtensions
{
public ThisNameSpace.User ToThisUser(this OtherNameSpace.User source)
{
return new ThisNameSpace.User
{
FirstName = source.FirstName,
LastName = source.LastName,
UserId = source.UserId
}
}
}
To me that's the simplest.
You could also use Automapper (add from Nuget.)
Do a one-time configuration:
AutoMapper.Mapper.Initialize(c=>c.CreateMap<User,Other.User>());
and then you can call it to map an instance of User to a new instance of Other.User.
var other = AutoMapper.Mapper.Map<Other.User>(user);
It works without specifying the mapping for individual properties if the property names and types are identical.
You can use reflection:
using System.Windows.Forms;
using System.Reflection;
namespace First
{
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserID { get; set; }
public User()
{
}
}
}
namespace Second
{
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserID { get; set; }
public User()
{
}
}
}
namespace YetAnotherNamespace
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
First.User user = new First.User()
{
FirstName = "John",
LastName = "Public",
UserID = "jpublic#mydomain.com"
};
Second.User newUser = ConvertUser(user);
}
public Second.User ConvertUser(First.User oldUser)
{
Second.User newUser = new Second.User();
foreach (PropertyInfo prop in oldUser.GetType().GetProperties())
{
string propertyName = prop.Name;
object propertyValue = prop.GetValue(oldUser);
newUser.GetType().GetProperty(propertyName).SetValue(newUser, propertyValue);
}
return newUser;
}
}
}
In this code sample, when I instantiate the form, I create a First.User and convert it to a Second.User.
This is tested and working (as a strongly-typed method). I think you can make it more generic and accept and return an "object", and it will just throw an exception if the properties don't match up. Also keep in mind that reflection tends to be slow - this may not be the most scalable solution.
Another approach would be serializing to json and then deserializing to the other type.

How to return specific set of data from a class

I have a similar structure to the one below
Base class
public class BaseClass
{
public string Name { get; set; }
public string Address { get; set; }
public int Age { get; set; }
public Guid Guid { get; set; }
public string Hometown { get; set; }
}
Derived Class
public class DerivedClass : BaseClass
{
public List<DerivedClassDataItem> Data { get; set; }
}
Data class
public class DerivedClassDataItem
{
public string Datum1 { get; set; }
public string Datum2 { get; set; }
public string Datum3 { get; set; }
public string Datum4 { get; set; }
public int Datum5 { get; set; }
public DateTime Datum6 { get; set; }
}
What is the best practice to return specific set of info from the DerivedClass?
a potential set could be:
Name, Address, Guid and then a Data list that only contains Datum1 and Datum4
I could see anonymousTypes, Tuples or another set of class(es), all to be valid approaches.
My concern about creating new set of classs for the set returned is that the class(s) structure will be similar to the structure of the three mentioned above except it will have fewer selected members, which to me, does not sound ideal. (duplicate code and structure)
Using anonymousTypes was my initial solution to tackle this, something like
List<DerivedClass> list = new List<DerivedClass>();
var mySet = list.Select(d => new
{
Name = d.Name,
Address = d.Address,
.
.
.
.
.
Data = d.Data.Select(item => new
{
Datum1 = item.Datum1,
Datum4 = item.Datum4
})
});
but again, that was a headache for us to track through httpResponse and through out API calls.
Should I go with Tuple?
Any insights as to what is the best practice for doing this?
Edit
I am using this set of data to be a response returned by a API/GET call. I will send the set back using HttpRespose and then the framework will transform that into json
this is an actual method we have now
private void populateReturnFile()
{
var returnFileAnonymous = new
{
Vendor = this.Vendor,
OrganizationName = this.OrganizationName,
User = this.User,
Platform = this.Platform,
DictionaryType = this.DictionaryType,
UseCaseId = this.UseCaseId,
Data = this.Data.Select(d => new
{
MigrationTermId = d.MigrationTermId,
ImoLexicalCode = d.ImoLexicalCode
})
};
this.returnFile = returnFileAnonymous;
}
Then my GET will return the retunFile (this is a very simple method, i have remove irrelevant code)
[HttpGet]
public HttpResponseMessage Get(Guid migrationFileId)
{
ProblemList problemList = ProblemList.GetProblemList(migrationFileId);
return Request.CreateResponse(HttpStatusCode.OK, problemList.ReturnFile, new JsonMediaTypeFormatter());
}
If API calls is where you are using these classes, then I personally like to keep it simple and avoid complex inheritance hierarchy. Remember, simple code is good code.
I would make a separate class for each api request/response call. For very simple api calls (ajax requests for example) I like to use anonymous types, but for controllers that only handle API calls I like to create separate classes, organized in a nice folder structure.
Everyone has their "style" but as long as you strive for simplicity your code will be maintainable.

Joining two lists of different types and sort them by date

I have a first list of entities like this :
public partial class Networking :EntityBase
{
public virtual int NetWorkingId
{
get;
set;
}
public virtual string NetWorkingParam
{
get;
set;
}
public virtual System.DateTime NetWorkingDate
{
get;
set;
}
}
And I have a second list of entities like this:
public partial class PrivateNetwork :EntityBase
{
public virtual int PrivateNetworkId
{
get;
set;
}
public virtual int ContaId
{
get { return _contaId; }
set
{
if (_contaId != value)
{
if (Contact != null && Contact.ContaId != value)
{
Contact = null;
}
_contaId = value;
}
}
}
public virtual Nullable<System.DateTime> DateCreation
{
get;
set;
}
}
I want to collect these two lists in one and sort all the elements by date.
Is that possible ?
You can do this, although it's not very pretty, and you end up with an IEnumerable<object> so you have to check each item's type before you can use it:
IEnumerable<object> sorted = myNetworkingList
.Concat<object>(myPrivateNetworkList)
.OrderBy(n => n is Networking
? (DateTime?)((Networking)n).NetWorkingDate
: ((PrivateNetwork)n).DateCreation);
foreach (object either in sorted)
{
if (either is Networking)
// Networking; do something
else
// PrivateNetwork; do something else
}
This problem could easily be solved by using polymorphism; use a common base class or interface for both classes, which has the DateTime property you want to sort on.
Example:
public abstract class NetworkingBase : EntityBase
{
public DateTime DateToSortOn { get; set; }
}
or
public interface INetworking
{
public DateTime DateToSortOn { get; set; }
}
And then make your classes derive from NetworkingBase or implement INetworking:
public partial class Networking : NetworkingBase
{
...
}
public partial class PrivateNetwork : NetworkingBase
{
...
}
or
public partial class Networking : EntityBase, INetworking
{
...
}
public partial class PrivateNetwork : EntityBase, INetworking
{
...
}
Do a LINQ Union or Concat and then an OrderBy on the resulting collection.
What I should have asked earlier is . . .
What do you want to do after you've sorted them?
The answer to this could have a big impact on the potential solution.
If the answer is something like I need to display a list of the dates, where you only need the dates in order. If so then you don't need to merge the two lists, you can get a sequence of just the ordered dates and use that e.g.
var orderedDates = networks.Select(n => n.NetworkingDate)
.Union(privateNetworks.Select(n => n.DateCreation))
.OrderBy(date => date);
If the answer is I need to display a list of links showing the Date that links to the Id of the object, and something to identify the type of object, then you could get away with something very like the above, with an Anonymous object.
var orderedDates = networks.Select(n => new {Date = n.NetworkingDate, Id = n.NetWorkingId, NetworkType = n.GetType().Name})
.Union(privateNetworks.Select(n => new {Date = n.DateCreation, Id = n.PrivateNetWorkingId, NetworkType = n.GetType().Name}))
.OrderBy(n => n.Date);
However if the answer is I need to send a Shutdown() command to the 10 oldest networks then you really do need a polymorphic solution, where you have a single type that you can call a Shutdown() method on, that will resolve to the specific Shutdown() method on the types you're using.
A Polymorphic solution to use only if user khellang's answer doesn't work for you
From a comment on another answer
#BinaryWorrier I chose this answer because I already have records in
the database, so if I choose to add a new interface how will I deal
with the records already stored before adding the interface ?
I find it difficult to believe that your ORM won't allow you to add an interface to an entity class and not - somehow - mark that interface and/or it's member so they're ignored by the ORM.
However, assuming you can't add a new interface or base class, you can still do this polymorphically.
Add the interface, add a class implementing the interface that for each of your Network classes (the Abstractor classes), then transform the network classes into Abstractor classes, adding them to a List<INetwork> and sorting that list.
public interface INetwork
{
DateTime? Date { get; }
}
public class PrivateNetworkAbstractor
:INetwork
{
private PrivateNetwork network;
public PrivateNetworkAbstractor(PrivateNetwork network)
{
this.network = network;
}
public DateTime? Date
{
get { return network.DateCreation; }
}
}
public class NetworkingAbstractor
: INetwork
{
private Networking networking;
public NetworkingAbstractor(Networking networking)
{
this.networking = networking;
}
public DateTime? Date
{
get { return networking.NetWorkingDate; }
}
}
...
public IEnumerable<INetwork> MergenSort(IEnumerable<Networking> generalNetWorks, IEnumerable<PrivateNetwork> privateNetWorks)
{
return generalNetWorks.Select(n => new NetworkingAbstractor(n)).Cast<INetwork>()
.Union(privateNetWorks.Select(n => new PrivateNetworkAbstractor(n)).Cast<INetwork>())
.OrderBy(n=> n.Date);
}
Create an interface that has the date and implement in in both classes. After that sorting is easy.
public interface INetwork
{
DateTime? Date { get; }
}
public partial class Networking :EntityBase, INetwork
{
public DateTime? Date
{
get { return NetWorkingDate; }
}
}
public partial class PrivateNetwork :EntityBase, INetwork
{
public DateTime? Date
{
get { return DateCreation; }
}
}
var commonList = new List<INetwork>();
// Add instances of PrivateNetwork and Networking to the list
var orderedByDate = commonList.OrderBy(n => n.Date);
First solution is using anonymous type
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Example1
{
class Program
{
class Human
{
public string Name { get; set; }
public string Hobby { get; set; }
public DateTime DateOfBirth { get; set; }
}
class Animal
{
public string Name { get; set; }
public string FavouriteFood { get; set; }
public DateTime DateOfBirth { get; set; }
}
static void Main(string[] args)
{
var humans = new List<Human>
{
new Human
{
Name = "Kate",
Hobby = "Fitness",
DateOfBirth = DateTime.Now.AddYears(-27),
},
new Human
{
Name = "John",
Hobby = "Cars",
DateOfBirth = DateTime.Now.AddYears(-32),
},
};
var animals = new List<Animal>
{
new Animal
{
Name = "Fluffy",
FavouriteFood = "Grain",
DateOfBirth = DateTime.Now.AddYears(-2),
},
new Animal
{
Name = "Bongo",
FavouriteFood = "Beef",
DateOfBirth = DateTime.Now.AddYears(-6),
},
};
var customCollection = (from human in humans
select new
{
Name = human.Name,
Date = human.DateOfBirth,
}
).Union(from animal in animals
select new
{
Name = animal.Name,
Date = animal.DateOfBirth,
}).OrderBy(x => x.Date);
foreach (dynamic customItem in customCollection)
Console.WriteLine(String.Format("Date: {0}, Name: {1}", customItem.Date, customItem.Name));
Console.Read();
}
}
}
or without anonymous type (created CustomClass):
...
class CustomClass
{
public string Name { get; set; }
public DateTime Date { get; set; }
}
...
var customCollection = (from human in humans
select new CustomClass
{
Name = human.Name,
Date = human.DateOfBirth,
}
).Union(from animal in animals
select new CustomClass
{
Name = animal.Name,
Date = animal.DateOfBirth,
}).OrderBy(x => x.Date);
foreach (CustomClass customItem in customCollection)
Console.WriteLine(String.Format("Date: {0}, Name: {1}", customItem.Date, customItem.Name));
...
I simply added a base class and assigned it as the parent of both list's classes . and then simple did the union . it made the trick

Categories