Map complex type to anonymous object - automapper

Let's have well known complex type (CT, e.g. Dto from the example).
Let's have set of type converters (functions) transforming value of one type to another (e.g. int SubDto2ToInt(SubDto2 sub), string GuidToString(Guid gd)).
Is there any method, how to configure Automapper and tell him:
"Map CT using these provided Type Converters and create object of anonymous type."?
This would effectively:
go over all CT's properties (recursively)
check the list of converters
if any present for given property type, convert and add to the result
otherwise proceed the default way (put it "as is" to the result)
I have had partial success when I pre-created the anonymous type, but that does not make much sense, because I can then create "normal" target type and define classic mapping. So the point is to let the Automapper create the target type on his own. The target member types would then be driven by either the source type or the conversion result type (if registered).
Example:
class SubDto1 { int M1; int M2; } // Pretend they are get/set properties
class SubDto2 { int N1; int N2; } // dtto
class Dto { SubDto1 Sub1; SubDto2 Sub2; Guid Id; } // dtto
var source = new Dto { Sub1 = new SubDto1 {M1 = 1, M2 = 2}, Sub2 = new SubDto2 {N1 = 10, N2 = 20}, Id = Guid.NewGuid()};
var expectedTargetEquivalentTo = new
{
Sub1 = new {M1 = 1, M1 = 2}, // No conversion registered here, "as is"
Sub2 = 30, // Fancy SubDto2 -> int conversion registered here
Id = "00000000-0000-0000-0000-000000000000", // Guid -> string conversion registered here
}

Related

Flutter access model attribute using dynamic key [duplicate]

I'm trying to access a class value by using a variable previously defined in dart, but I keep getting the error the operator [] isn't defined for the class
In Javascript I would access an object value using a variable like this:
let movie = {
movieTitle : 'Toy Story',
actor: 'Tom Hanks'
}
let actorName = 'actor';
console.log(movie[actorName]); // <- what I'm trying to replicate in dart
// expected output: Tom Hanks
Here is what I've tried and is throwing that error
class Movie {
String name;
String actor;
String producer;
}
void main() {
var movieTitle = new Movie();
movieTitle.name = 'Toy Story';
movieTitle.actor = 'Tom Hanks';
print(movieTitle.actor); <- prints out Tom Hanks as expected
var actorName = 'actor';
print(movieTitle[actorName]); <- throws error
}
I expect to be able to use a variable on the fly to access the value.
A trivial use case for me would be if I had a a list of Movie classes, where some actors and producers are null, I would like to filter on either non null actors or producer with a function like so:
List values = movieList.where((i) => i.actor != "null").toList(); // returns all Movies in movieList where the actor value isn't the string "null"
var actorIsNull = 'actor';
List values = movieList.where((i) => i[actorisNull] != "null").toList(); // throws error
You can createn a toMap() function in your Movie class and access properties using [] operator
class Movie {
String name;
String actor;
String producer;
Map<String, dynamic> toMap() {
return {
'name': name,
'actor' : actor,
'producer' : producer,
};
}
}
Now Movie class properties can be accessed as:
Movie movie = Movie();
movie.toMap()['name'];
You cannot access class members by a string containing their name. (Except with mirrors - outside the scope of this answer.)
You could remove the class altogether and just use a Map<String, String>.
Map<String, String> movie = {
'movieTitle': 'Toy Story',
'actor': 'Tom Hanks',
}
You could add some bool methods on the class.
bool hasNoActor() => actor == null;
...
List values = movieList.where((m) => !m.hasNoActor()).toList();
Or, you could pass a lambda to your mapper.
Movie movieTitle = Movie()
..name = 'Toy Story'
..actor = 'Tom Hanks';
Function hasActor = (Movie m) => m.actor != null;
List values = movieList.where(hasActor).toList();

Access String value in enum without using rawValue

I would like to replace my global string constants with a nested enum for the keys I'm using to access columns in a database.
The structure is as follows:
enum DatabaseKeys {
enum User: String {
case Table = "User"
case Username = "username"
...
}
...
}
Each table in the database is an inner enum, with the name of the table being the enum's title. The first case in each enum will be the name of the table, and the following cases are the columns in its table.
To use this, it's pretty simple:
myUser[DatabaseKeys.User.Username.rawValue] = "Johnny"
But I will be using these enums a lot. Having to append .rawValue to every instance will be a pain, and it's not as readable as I'd like it to be. How can I access the String value without having to use rawValue? It'd be great if I can do this:
myUser[DatabaseKeys.User.Username] = "Johnny"
Note that I'm using Swift 2. If there's an even better way to accomplish this I'd love to hear it!
While I didn't find a way to do this using the desired syntax with enums, this is possible using structs.
struct DatabaseKeys {
struct User {
static let identifier = "User"
static let Username = "username"
}
}
To use:
myUser[DatabaseKeys.User.Username] = "Johnny"
Apple uses structs like this for storyboard and row type identifiers in the WatchKit templates.
You can use CustomStringConvertible protocol for this.
From documentation,
String(instance) will work for an instance of any type, returning its
description if the instance happens to be CustomStringConvertible.
Using CustomStringConvertible as a generic constraint, or accessing a
conforming type's description directly, is therefore discouraged.
So, if you conform to this protocol and return your rawValue through the description method, you will be able to use String(Table.User) to get the value.
enum User: String, CustomStringConvertible {
case Table = "User"
case Username = "username"
var description: String {
return self.rawValue
}
}
var myUser = [String: String]()
myUser[String(DatabaseKeys.User.Username)] = "Johnny"
print(myUser) // ["username": "Johnny"]
You can use callAsFunction (New in Swift 5.2) on your enum that conforms to String.
enum KeychainKey: String {
case userId
case email
}
func callAsFunction() -> String {
return self.rawValue
}
usage:
KeychainKey.userId()
You can do this with custom class:
enum Names: String {
case something, thing
}
class CustomData {
subscript(key: Names) -> Any? {
get {
return self.customData[key.rawValue]
}
set(newValue) {
self.customData[key.rawValue] = newValue
}
}
private var customData = [String: Any]()
}
...
let cData = CustomData()
cData[Names.thing] = 56
Edit:
I found an another solution, that working with Swift 3:
enum CustomKey: String {
case one, two, three
}
extension Dictionary where Key: ExpressibleByStringLiteral {
subscript(key: CustomKey) -> Value? {
get {
return self[key.rawValue as! Key]
}
set {
self[key.rawValue as! Key] = newValue
}
}
}
var dict: [String: Any] = [:]
dict[CustomKey.one] = 1
dict["two"] = true
dict[.three] = 3
print(dict["one"]!)
print(dict[CustomKey.two]!)
print(dict[.three]!)
If you are able to use User as dictionary key instead of String (User is Hashable by default) it would be a solution.
If not you should use yours with a nested struct and static variables/constants.

Spock unit testing and Inner closures

I ran into a rather odd closure issue related to spock unit testing and wondered if anyone could explain this.
If we imagine a dao, model, and service as follows:
interface CustomDao {
List<Integer> getIds();
Model getModelById(int id);
}
class CustomModel {
int id;
}
class CustomService {
CustomDao customDao
public List<Object> createOutputSet() {
List<Model> models = new ArrayList<Model>();
List<Integer> ids = customDao.getIds();
for (Integer id in ids) {
models.add(customDao.getModelById(id));
}
return models;
}
}
I would like to unit test the CustomService.createOutputSet. I have created the following specification:
class TestSpec extends Specification {
def 'crazy closures'() {
def mockDao = Mock(CustomDao)
def idSet = [9,10]
given: 'An initialized object'
def customService = new CustomService
customService.customDao = mockDao
when: 'createOutput is called'
def outputSet = customService.createOutputSet()
then: 'the following methods should be called'
1*mockDao.getIds() >> {
return idSet
}
for (int i=0; i<idSet.size(); i++) {
int id = idSet.get(i)
1*mockDao.getModelById(idSet.get(i)) >> {
def tmp = new Model()
int tmpId = id // idSet.get(i)
return tmp
}
}
and: 'each compute package is accurate'
2 == outputSet.size()
9 == outputSet.get(0).getId()
10 == outputSet.get(1).getId()
}
}
Notice that in here I test two things. First, I initialize the dao with my mock, verify that the daos are correctly called and return the proper data, and then I verify that I get the proper output (i.e. "and:").
The tricky part is the for loop, in which I wanted to return models from the mock dao that are related to the method parameter. In the above example, if I use a simple for (__ in idSet), the models only return with id 10: outputSet.get(0).getId() == outputSet.get(1).getId() == 10. If I use the traditional for loop, and set the model with idSet.get(i), I get an IndexOutOfBoundsException . The only way to make this work is by retrieving the value in a local variable (id) and setting with variable, as above.
I know this is related to groovy closures and I suspect that spock captures the mock calls into a set of closures before executing them, which means that the model creation depends on the outer state of the closure. I understand why I would get the IndexOutOfBoundsException, but I don't understand why int id = idSet.get(i) is captured by the closure whereas i is not.
What is the difference?
Note: this is not the live code but rather simplified to demonstrate the crux of my challenge. I would not and do not make two subsequent dao calls on getIds() and getModelById().
While stubbing getModelById by a closure, the arguments to the closure has to match with that of the method. If you try something like below, you would not need the local variable id inside for anymore.
for (int i=0; i<idSet.size(); i++) {
//int id = idSet.get(i)
mockDao.getModelById(idSet.get(i)) >> {int id ->
def tmp = new Model()
tmp.id = id // id is closure param which represents idSet.get(i)
return tmp
}
}
Simplified version would be to use each
idSet.each {
mockDao.getModelById(it) >> {int id ->
def tmp = new Model()
tmp.id = id // id is closure param which represents idSet.get(i)
tmp
}
}
Do we need to worry about how many times method is called if it is being stubbed?
Accessing mutable local variables from a closure whose execution is deferred is a common source of errors not specific to Spock.
I don't understand why int id = idSet.get(i) is captured by the closure whereas i is not.
The former gives rise to a separate hoisted variable per iteration whose value is constant. The latter gives rise to a single hoisted variable whose value changes over time (and before the result generator executes).
Instead of solving the problem by introducing a temporary variable, a better solution (already given by #dmahapatro) is to declare an int id -> closure parameter. If it's deemed good enough to stub the calls without enforcing them, the loop can be omitted altogether. Yet another potential solution is to construct the return values eagerly:
idSet.each { id ->
def model = new Model()
model.id = id
1 * mockDao.getModelById(id) >> model
}

Dynamically create an object from an anonymous object

Using a type builder I am OK with creating a type dynamically. Would it be possible to do this from an anonymous type?
I have this so far;
//CreateType generates a type (so that I can set it's properties once instantiated) from an //anonymous object. I am not interested in the initial value of the properties, just the Type.
Type t = CreateType(new {Name = "Ben", Age = 23});
var myObject = Activator.CreateInstance(t);
Is it possible to now use Type "t" as a type argument?
My method:
public static void DoSomething<T>() where T : new()
{
}
I would like to call this method using the dynamically created Type "t". So that I can call;
DoSomething<t>(); //This won't work obviously
Yes, it is possible. To use the type as a type argument, you need to use the MakeGenericType method:
// Of course you'll use CreateType here but this is what compiles for me :)
var anonymous = new { Value = "blah", Number = 1 };
Type anonType = anonymous.GetType();
// Get generic list type
Type listType = typeof(List<>);
Type[] typeParams = new Type[] { anonType };
Type anonListType = listType.MakeGenericType(typeParams);
// Create the list
IList anonList = (IList)Activator.CreateInstance(anonListType);
// create an instance of the anonymous type and add it
var t = Activator.CreateInstance(anonType, "meh", 2); // arguments depending on the constructor, the default anonymous type constructor just takes all properties in their declaration order
anonList.Add(t);

Anonymous type and getting values out side of method scope

I am building an asp.net site in .net framework 4.0, and I am stuck at the method that supposed to call a .cs class and get the query result back here is my method call and method
1: method call form aspx.cs page:
helper cls = new helper();
var query = cls.GetQuery(GroupID,emailCap);
2: Method in helper class:
public IQueryable<VariablesForIQueryble> GetQuery(int incomingGroupID, int incomingEmailCap)
{
var ctx = new some connection_Connection();
ObjectSet<Members1> members = ctx.Members11;
ObjectSet<groupMember> groupMembers = ctx.groupMembers;
var query = from m in members
join gm in groupMembers on m.MemberID equals gm.MemID
where (gm.groupID == incomingGroupID) && (m.EmailCap == incomingEmailCap)
select new VariablesForIQueryble(m.MemberID, m.MemberFirst, m.MemberLast, m.MemberEmail, m.ValidEmail, m.EmailCap);
//select new {m.MemberID, m.MemberFirst, m.MemberLast, m.MemberEmail, m.ValidEmail, m.EmailCap};
return query ;
}
I tried the above code with IEnumerable too without any luck. This is the code for class VariablesForIQueryble:
3:Class it self for taking anonymouse type and cast it to proper types:
public class VariablesForIQueryble
{
private int _emailCap;
public int EmailCap
{
get { return _emailCap; }
set { _emailCap = value; }
}`....................................
4: and a constructor:
public VariablesForIQueryble(int memberID, string memberFirst, string memberLast, string memberEmail, int? validEmail, int? emailCap)
{
this.EmailCap = (int) emailCap;
.........................
}
I can't seem to get the query result back, first it told me anonymous type problem, I made a class after reading this: link text; and now it tells me constructors with parameters not supported. Now I am an intermediate developer, is there an easy solution to this or do I have to take my query back to the .aspx.cs page.
If you want to project to a specific type .NET type like this you will need to force the query to actually happen using either .AsEnumerable() or .ToList() and then use .Select() against linq to objects.
You could leave your original anonymous type in to specify what you want back from the database, then call .ToList() on it and then .Select(...) to reproject.
You can also clean up your code somewhat by using an Entity Association between Groups and Members using a FK association in the database. Then the query becomes a much simpler:
var result = ctx.Members11.Include("Group").Where(m => m.Group.groupID == incomingGroupID && m.EmailCap == incomingEmailCap);
You still have the issue of having to do a select to specify which columns to return and then calling .ToList() to force execution before reprojecting to your new type.
Another alternative is to create a view in your database and import that as an Entity into the Entity Designer.
Used reflection to solve the problem:
A: Query, not using custom made "VariablesForIQueryble" class any more:
//Method in helper class
public IEnumerable GetQuery(int incomingGroupID, int incomingEmailCap)
{
var ctx = new some_Connection();
ObjectSet<Members1> members = ctx.Members11;
ObjectSet<groupMember> groupMembers = ctx.groupMembers;
var query = from m in members
join gm in groupMembers on m.MemberID equals gm.MemID
where ((gm.groupID == incomingGroupID) && (m.EmailCap == incomingEmailCap)) //select m;
select new { m.MemberID, m.MemberFirst, m.MemberLast, m.MemberEmail, m.ValidEmail, m.EmailCap };
//select new VariablesForIQueryble (m.MemberID, m.MemberFirst, m.MemberLast, m.MemberEmail, m.ValidEmail, m.EmailCap);
//List<object> lst = new List<object>();
//foreach (var i in query)
//{
// lst.Add(i.MemberEmail);
//}
//return lst;
//return query.Select(x => new{x.MemberEmail,x.MemberID,x.ValidEmail,x.MemberFirst,x.MemberLast}).ToList();
return query;
}
B:Code to catch objects and conversion of those objects using reflection
helper cls = new helper();
var query = cls.GetQuery(GroupID,emailCap);
if (query != null)
{
foreach (var objRow in query)
{
System.Type type = objRow.GetType();
int memberId = (int)type.GetProperty("MemberID").GetValue(objRow, null);
string memberEmail = (string)type.GetProperty("MemberEmail").GetValue(objRow, null);
}
else
{
something else....
}

Resources