Enum value in tuple using ServiceStack Ormlite throws null reference exception - servicestack

I get "Object reference not set to an instance of an object" when using the Tuple notation with an Enum in the return structure.
If I change the type in the tuple from Enum type to string it works as it should, also if I change it to return only one value (string or enum) it works as it should.
It it a bug in ServiceStack?
I am running ServiceStack.OrmLite.SqlServer v5.4.0 in LinqPad v5.31.0
void Main()
{
var uniqueId = "a635266024448923446";
var result = new Dictionary<Language, string>();
using (var db = _connectionFactory.OpenDbConnection())
{
// This works fine
var rows1 = db.Select<A>("select LanguageId, Name from tblTable");
foreach (var row in rows1)
{
result.Add(row.LanguageId, row.Name);
}
}
using (var db = _connectionFactory.OpenDbConnection())
{
// This throws "Object reference not set to an instance of an object."
var rows2 = db.Select<(Language Language, string Name)>("select LanguageId, Name from tblTable");
foreach (var row in rows2)
{
result.Add(row.Language, row.Name);
}
}
}
public class A
{
public Language LanguageId { get; set; }
public string Name { get; set; }
}
public enum Language
{
NO,
EN,
SV,
DK
}

This change should be resolved from this commit.
This change is available from v5.4.1 that's now available on MyGet.

Related

How to determine type of a dynamic property at runtime

I have a simple POCO class with one one public property defined as dynamic. Is it possible to determine the type of this property at runtime?
I've tried getting the type using reflection like this:
myObject.GetType().GetProperties();
or this:
System.ComponentModel.TypeDescriptor.GetProperties(myObject);
But both return System.Object rather than the current type.
In the Visual Studio debugger I see the type listed as "dynamic {System.DateTime}" or "dynamic {System.Int32}" which suggests it's possible to read the type at runtime. So how does one do it?
Edit - Adding a sample program that shows the issue:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DynamicTypeSample
{
class Program
{
static void Main(string[] args)
{
DataTag datatag1 = new DataTag() { Id = Guid.NewGuid(), Name = "datatag1", Value = new DateTime(2014, 9, 12) };
DataTag datatag2 = new DataTag() { Id = Guid.NewGuid(), Name = "datatag2", Value = (int)1234 };
var propertyTypes1 = GetPropertyTypes(datatag1);
var propertyTypes2 = GetPropertyTypes(datatag2);
foreach (var p in propertyTypes1)
{
Console.WriteLine(p.Key + " " + p.Value.ToString());
}
foreach (var p in propertyTypes2)
{
Console.WriteLine(p.Key + " " + p.Value.ToString());
}
Console.ReadLine();
}
private static Dictionary<string, Type> GetPropertyTypes(DataTag datatag)
{
Dictionary<string, Type> results = new Dictionary<string, Type>();
foreach (var pi in (typeof(DataTag)).GetProperties())
{
results.Add(pi.Name, pi.PropertyType);
}
return results;
}
}
public class DataTag
{
public Guid Id { get; set; }
public string Name { get; set; }
public dynamic Value { get; set; }
}
}
The output looks like:
Id Sytem.Guid
Name System.String
Value System.Object
Id Sytem.Guid
Name System.String
Value System.Object
What I'm trying to achieve is:
Id Sytem.Guid
Name System.String
Value System.DateTime
Id Sytem.Guid
Name System.String
Value System.Int32
If I’m not mistaken. What you are doing over there is getting the object properties.
What you could do is use reflection to iterate through the properties to get their basic info and data type.
Maybe you should try something like this :
PropertyInfo[] propsobj = typeof(MyClassType).GetProperties();
foreach(PropertyInfo p in propsobj)
{
object[] attribs = p.MyProperty;
}
Hope it helps.
Cheers!

Automapper error: Expressions mapping from methods not supported yet

Any idea what might cause the error "Expressions mapping from methods not supported yet." when trying to map two objects? I cannot find any reference to this error anywhere.
EDITED---
I have more information. I have a property in my DTO declared as:
public LookupItem RegionType { get; set; }
However, when I invoke the mapping, it generates the error, "Expressions mapping from methods not supported yet.".
However, if I change the string in the property name "Type" to anything else like "Typeo" or "ASDF", the mapping succeeds. In other words, if change the property name to "RegionTypeo". Am I breaking any convention rules here? There seems to be something wrong with including the string "Type" in my property name.
Below is the generated error:
Result Message:
Test method Rep.Tests.PlanServiceTest.GetBuildings threw exception:
System.NotImplementedException: Expressions mapping from methods not supported yet.
Result StackTrace:
at AutoMapper.PropertyMap.ResolveExpression(Type currentType, Expression instanceParameter)
at AutoMapper.QueryableExtensions.Extensions.CreateMemberBindings(IMappingEngine mappingEngine, Type typeIn, TypeMap typeMap, Expression instanceParameter)
at AutoMapper.QueryableExtensions.Extensions.CreateMapExpression(IMappingEngine mappingEngine, Type typeIn, Type typeOut, Expression instanceParameter)
at AutoMapper.QueryableExtensions.Extensions.CreateMapExpression(IMappingEngine mappingEngine, Type typeIn, Type typeOut)
at AutoMapper.QueryableExtensions.Extensions.<>c__DisplayClass12.<CreateMapExpression>b__0(TypePair tp)
at System.Collections.Concurrent.ConcurrentDictionary2.GetOrAdd(TKey key, Func2 valueFactory)
at AutoMapper.Internal.DictionaryFactoryOverride.ConcurrentDictionaryImpl2.GetOrAdd(TKey key, Func2 valueFactory)
at AutoMapper.QueryableExtensions.Extensions.CreateMapExpression[TSource,TDestination](IMappingEngine mappingEngine)
at AutoMapper.QueryableExtensions.ProjectionExpression1.ToTResult
at Rep.Services.PlanService.GetBuildings() in c:\Dev\REP\Rep\Services\PlanService.cs:line 369
at Rep.Tests.PlanServiceTest.GetBuildings() in c:\Dev\REP\Rep.Tests\PlanServiceTest.cs:line 50
Based on the source code, you can see that the exception is thrown when you try mapping functions on your objects:
public ExpressionResolutionResult ResolveExpression(Type currentType, Expression instanceParameter)
{
Expression currentChild = instanceParameter;
Type currentChildType = currentType;
foreach (var resolver in GetSourceValueResolvers())
{
var getter = resolver as IMemberGetter;
if (getter != null)
{
var memberInfo = getter.MemberInfo;
var propertyInfo = memberInfo as PropertyInfo;
if (propertyInfo != null)
{
currentChild = Expression.Property(currentChild, propertyInfo);
currentChildType = propertyInfo.PropertyType;
}
else
{
throw new NotImplementedException("Expressions mapping from methods not supported yet.");
}
}
else
{
var oldParameter = CustomExpression.Parameters.Single();
var newParameter = instanceParameter;
var converter = new ConversionVisitor(newParameter, oldParameter);
currentChild = converter.Visit(CustomExpression.Body);
currentChildType = currentChild.Type;
}
}
return new ExpressionResolutionResult(currentChild, currentChildType);
}
Based on OP clarification, I cannot reproduce the problem with the following:
public class Class1
{
public string StringType { get; set; }
public Func<Class1> FuncType { get; set; }
public Class1 Class1Type { get; set; }
}
public class Class2
{
public string StringType { get; set; }
public Func<Class1> FuncType { get; set; }
public Class1 Class1Type { get; set; }
}
/* ... */
AutoMapper.Mapper.CreateMap<Class1, Class2>();
var c1 = new Class1() { Class1Type = new Class1(), FuncType = () => new Class1(), StringType = "Class1" };
var c2 = AutoMapper.Mapper.Map<Class1, Class2>(new Class1());

foreach collection reference type nested property update

I see numerous examples on foreach collection reference type property update, but not quite what I am struggling with. What if you want to update a property of a property of the reference type item? like so:
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public EmployeeType EmpType { get; set; }
}
public class EmployeeType
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Class1
{
private IList<Employee> existingEmp;
public void edit()
{
var dbEmployees = GetExistingEmployees();
IList<Employee> employees = new List<Employee> {
new Employee{ Id = 1, Name="me", EmpType = new EmployeeType { Id = 1}},
new Employee{ Id = 2, Name="me again", EmpType = new EmployeeType { Id = 2}}
};
foreach (var emp in employees)
{
foreach (var oldEmp in dbEmployees)
{
if (emp.Id == oldEmp.Id)
{
UpdateChanges(emp, oldEmp);
existingEmp.Add(oldEmp);
}
}
}
}
private void UpdateChanges(Employee emp, Employee oldEmp){
if (oldEmp.EmpType.Id != emp.EmpType.Id)
{
LogChange();
oldEmp.EmpType.Id = emp.EmpType.Id;
}
}
private void LogChange()
{
throw new NotImplementedException();
}
//data access layer
public IList<Employee> GetExistingEmployees()
{
throw new NotImplementedException();
}
}
The issue here is the last employee in the collection if his/her employee type property Id changed in a ddl, updating it will cascade to all other employees' emp type in the collection. That is nutts. Due to the logging requirement I can not use lambda or other fancy construct. I need hep with fixing this with in foreach or for loops.
EDIT:
As expected the same code structure works somewhere else in my application. I don't get the last item's property updating bleeding to other items' properties.
I solved this using a hacky approach:
private void UpdateChanges(Employee emp, Employee oldEmp){
var oldEmpTemp = GetEmployeeById(oldEmp.Id);
if (oldEmp.EmpType.Id != emp.EmpType.Id)
{
LogChange();
oldEmpTemp.EmpType.Id = emp.EmpType.Id;
}
//instead of updating the collection items
// and bulk updating in the db, update directly in the db
UpdateEmployee(oldEmpTemp);
}
But still can't explain why it's not working for this instance.

Neo4jClient is not returning properties for a node in .Return

I am trying to use Neo4jClient (and am new to C#) to build and retrieve data from Neo4j. First, I build the items and relations to a search:
NodeReference<Search> searchNode = client.Create(searches[i]);
itmNode = client.Create(items[j], new IRelationshipAllowingParticipantNode<Item>[0],
new[]
{
new IndexEntry("Item")
{
{"Type", items[j].Type },
{"ItemDescription", items[j].ItemDescription },
{"ItemNumber", items[j].ItemNumber }
}
});
client.CreateRelationship(itmNode, new SearchedFor(searchNode, 1));
Then, I am testing the retrieval of the node back from Neo4j:
var results = client.Cypher.Start("n", itemDict[firstitem])
.Match("n-[r]->()<-[r2]-other")
.Return<Node<Item>>("other")
.Results;
var node6 = ((IRawGraphClient)client).ExecuteGetCypherResults<Node<Item>>(new Neo4jClient.Cypher.CypherQuery("start n=node(6) return n;", null,Neo4jClient.Cypher.CypherResultMode.Set)).Select(un => un.Data);
"results" returns the 2 nodes that are related to node(6). "node6" is other code I found that I thought would return node 6. Both of these return the nodes, but the properties returned are all blank. I can see the properties in the Neo4j Monitoring Tool, but not when they are returned using Neo4jClient. Am I missing something in how I am setting up the nodes, or on how I am retrieving the data?
My object return shows Data.ItemDescription="", Data.ItemNumber=0, Reference=Node 5
Adding the "Select(un => un.Data)" after .Results did not work like I saw in other examples like this
Please let me know if you need more information.
Neo4jClient version 1.0.0.579
Neo4j version 1.8.2
Here is the item class:
public class Item
{
private string _name;
private string _desc;
private long _id;
public Item(string name, string desc, long id)
{
_name = name;
_desc = desc;
_id = id;
}
public Item()
{
_name = "";
_desc = "";
_id = 0;
}
public long ItemNumber
{
get
{
return _id;
}
}
public string ItemDescription
{
get
{
return _desc;
}
}
public string Type
{
get
{
return "Item";
}
}
}
Making it work
The issue is that your Item class has no setters exposed. There's no way for us to set those properties , so we ignore them.
You can delete half your code, and it'll work. :)
public class Item
{
public long ItemNumber { get; set; }
public string ItemDescription { get; set; }
public string Type { get ; set; }
}
Making it better
Replace this:
NodeReference<Search> searchNode = client.Create(searches[i]);
itmNode = client.Create(items[j], new IRelationshipAllowingParticipantNode<Item>[0],
new[]
{
new IndexEntry("Item")
{
{"Type", items[j].Type },
{"ItemDescription", items[j].ItemDescription },
{"ItemNumber", items[j].ItemNumber }
}
});
client.CreateRelationship(itmNode, new SearchedFor(searchNode, 1));
with this:
var searchNode = client.Create(searches[i]);
var itemNode = client.Create(
items[j],
new[] { new SearchedFor(searchNode, 1) }
new[]
{
new IndexEntry("Item")
{
{"Type", items[j].Type },
{"ItemDescription", items[j].ItemDescription },
{"ItemNumber", items[j].ItemNumber }
}
});
That will create that second node, and the relationship, in a single call.

Automapper: Mapping using attributes for non-matching properties

I have a scenario in which I'm creating a mapping utility through which we can map DataReader to entities.
Mapper.CreateMap<IDataReader, T>();
List<T> tList = Mapper.Map<List<T>>(reader);
return tList;
This is working fine if the entity has same columns as in the stored procedure's output. However, I'm working on an some old code where column names are not matching. So I created an attribute through which I could specify corresponding column from sprocs. I specify them using code like this
[DBColumn('EmployeeName')]
public string EmpName { get; set; }
Is there any way I can achieve this using generics/reflection? Note that I have multiple such instances and I'm building an utility. So I can not use ForMember method to achieve that.
UPDATE: I tried creating a custom converter like this. However, my convert function is not getting called at all.
Custom converter
public class CustomConverter<T> : ITypeConverter<System.Data.IDataReader, T>
{
private ResolutionContext _Context = null;
private Dictionary<string, string> _CustomProps { get; set; }
public T Convert(ResolutionContext context)
{
_Context = context;
if (_Context.SourceValue != null &&
!(_Context.SourceValue is System.Data.IDataReader))
{
string message = "Value supplied is of type {0} but expected {1}.\n" +
"Change the type converter source type, or redirect " +
"the source value supplied to the value resolver using FromMember.";
throw new AutoMapperMappingException(_Context, string.Format(
message, typeof(System.Data.IDataReader), _Context.SourceValue.GetType()));
}
_CustomProps = new Dictionary<string, string>();
foreach (PropertyInfo propInfo in context.DestinationType.GetProperties())
{
if (propInfo.CustomAttributes.Any(attr => attr.AttributeType == typeof(DBColumn)))
{
DBColumn propertyValue = (DBColumn)propInfo.GetCustomAttribute(typeof(DBColumn));
_CustomProps.Add(propertyValue.ColumnName, propInfo.Name);
}
}
//return base.Convert(context);
return ConvertCore((System.Data.IDataReader)context.SourceValue);
}
protected T ExistingDestination
{
get
{
if (_Context == null)
{
string message = "ResolutionContext is not yet set. " +
"Only call this property inside the 'ConvertCore' method.";
throw new InvalidOperationException(message);
}
if (_Context.DestinationValue != null &&
!(_Context.DestinationValue is T))
{
string message = "Destination Value is of type {0} but expected {1}.";
throw new AutoMapperMappingException(_Context, string.Format(
message, typeof(T), _Context.DestinationValue.GetType()));
}
return (T)_Context.DestinationValue;
}
}
protected T ConvertCore(System.Data.IDataReader source)
{
T obj = ExistingDestination;
if (obj != null)
{
foreach (KeyValuePair<string, string> keyValuePair in _CustomProps)
{
PropertyInfo prop = obj.GetType().GetProperty(keyValuePair.Key, BindingFlags.Public | BindingFlags.Instance);
if (null != prop && prop.CanWrite)
{
prop.SetValue(obj, System.Convert.ChangeType(source[keyValuePair.Value], prop.PropertyType));
}
}
}
return obj;
}
I'm specifying to use this CustomConverter in below statement.
Mapper.CreateMap<IDataReader, T>().ConvertUsing<CustomConverter<T>>();
List<T> tList = Mapper.Map<List<T>>(reader);
return tList;
Please let me know, where I'm going wrong

Resources