NHibernate AliasToBean transformer associations - c#

I'm trying to use the following statement to get an entity with the fields I'm after:
retVal = session.CreateCriteria(typeof(MyEntity))
.CreateAlias("MyEntityProperty", "MyEntityProperty")
.Add(Restrictions.Eq("MyEntityProperty.Year", year))
.SetProjection(
Projections.Distinct(
Projections.ProjectionList()
.Add(Projections.Property("Property1"), "Property1")
.Add(Projections.Property("Property2"), "Property2")
.Add(Projections.Property("MyEntityProperty.RegisteredUser"), "MyEntityProperty.RegisteredUser")
.Add(Projections.Property("MyEntityProperty.CompanyInfo"), "MyEntityProperty.CompanyInfo")
)
)
.SetResultTransformer(Transformers.AliasToBean(typeof(MyEntity)))
.List<MyEntity>()
.Cast<BaseMyEntity>();
MyEntity is the entity I want to return, and MyEntityProperty is a property of MyEntity that is another entity (of type MyEntityProperty).
The error I get is Could not find a setter for property 'MyEntityProperty.RegisteredUser' in class 'MyEntity'
Is the AliasToBean transformer not able to handle sub entities? Or is there something more I need to do to make it work?

There is my master piece... which I'm using to transform any level of projections depth. Take it and use it like this:
.SetResultTransformer(new DeepTransformer<MyEntity>())
It could be used for any ValueType properties, many-to-one references and also for dynamic objects...
public class DeepTransformer<TEntity> : IResultTransformer
where TEntity : class
{
// rows iterator
public object TransformTuple(object[] tuple, string[] aliases)
{
var list = new List<string>(aliases);
var propertyAliases = new List<string>(list);
var complexAliases = new List<string>();
for(var i = 0; i < list.Count; i++)
{
var aliase = list[i];
// Aliase with the '.' represents complex IPersistentEntity chain
if (aliase.Contains('.'))
{
complexAliases.Add(aliase);
propertyAliases[i] = null;
}
}
// be smart use what is already available
// the standard properties string, valueTypes
var result = Transformers
.AliasToBean<TEntity>()
.TransformTuple(tuple, propertyAliases.ToArray());
TransformPersistentChain(tuple, complexAliases, result, list);
return result;
}
/// <summary>Iterates the Path Client.Address.City.Code </summary>
protected virtual void TransformPersistentChain(object[] tuple
, List<string> complexAliases, object result, List<string> list)
{
var entity = result as TEntity;
foreach (var aliase in complexAliases)
{
// the value in a tuple by index of current Aliase
var index = list.IndexOf(aliase);
var value = tuple[index];
if (value.IsNull())
{
continue;
}
// split the Path into separated parts
var parts = aliase.Split('.');
var name = parts[0];
var propertyInfo = entity.GetType()
.GetProperty(name, BindingFlags.NonPublic
| BindingFlags.Instance
| BindingFlags.Public);
object currentObject = entity;
var current = 1;
while (current < parts.Length)
{
name = parts[current];
object instance = propertyInfo.GetValue(currentObject);
if (instance.IsNull())
{
instance = Activator.CreateInstance(propertyInfo.PropertyType);
propertyInfo.SetValue(currentObject, instance);
}
propertyInfo = propertyInfo.PropertyType.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
currentObject = instance;
current++;
}
// even dynamic objects could be injected this way
var dictionary = currentObject as IDictionary;
if (dictionary.Is())
{
dictionary[name] = value;
}
else
{
propertyInfo.SetValue(currentObject, value);
}
}
}
// convert to DISTINCT list with populated Fields
public System.Collections.IList TransformList(System.Collections.IList collection)
{
var results = Transformers.AliasToBean<TEntity>().TransformList(collection);
return results;
}
}

Well wasn't I making things more complicated than necessary.
Instead of trying to set the fields on the sub entity, all I needed to do was reference the entity field itself:
.Add(Projections.Property("MyEntityProperty"), "MyEntityProperty")
and nHibernate populated it fine.
But I'm glad I asked because I got Radim's very useful code :-)

Related

Casting ExpandoObject to AnonymousType of T

Im trying to clone an AnonymousType and enconter some strange behavior.
could anyone tell me why and also tell me a solution.
Here is a test code.
public static T DeepClone<T>(this T objectToBeCloned) where T : class
{
// this will always return null.
return Clone(objectToBeCloned) as T;
// if i try, it will work somehow
// var o = Clone(objectToBeCloned) as dynamic;
// if I try, will get an exception cant cast
// ExpandoObject to AnonymousType even thaugh i could cast it to dynamic
// var o = (T)Clone(objectToBeCloned);
}
// the clone method
public static object Clone(this object objectToBeCloned){
object resObject;
if (primaryType.IsAnonymousType()) // dynamic types
{
var props = FastDeepClonerCachedItems.GetFastDeepClonerProperties(primaryType);
resObject = new ExpandoObject();
var d = resObject as IDictionary<string, object>;
foreach (var prop in props.Values)
{
var item = prop.GetValue(objectToBeCloned);
if (item == null)
continue;
var value = prop.IsInternalType ? item : Clone(item);
if (!d.ContainsKey(prop.Name))
d.Add(prop.Name, value);
}
return resObject;
}
dynamic test = { p1="sd" };
var v =test.DeepClone(test);
// v is always null in this case dont understand why
This isn't the cleanest code, but it clones an anonymous type:
var original = new { Name = "Albert", Age = 99 };
var constructor = original.GetType().GetConstructors().First();
var parameters = constructor.GetParameters();
var properties = original.GetType().GetProperties();
var arguments =
(
from pa in parameters
join pr in properties on pa.Name equals pr.Name
select pr.GetValue(original)
).ToArray();
var clone = constructor.Invoke(arguments);
Not much use though as anonymous types are immutable.

How to get all the values from an SQL Query C#

I have used String Builder to generate a RAW SQL QUERY in C#.
List<string> columns = new List<string>();
columns.Add("id");
columns.Add("Temp");
StringBuilder SqlStatement = new StringBuilder();
SqlStatement.Append("Select ");
for (int i = 0; i < columns.Count; i++)
{
if (i == columns.Count - 1)
{
SqlStatement.Append(columns[i]);
}
else
{
SqlStatement.Append(columns[i]);
SqlStatement.Append(",");
}
}
SqlStatement.Append(" FROM graph_update");
var ctx = new graphDBContext();
var result = ctx.Database.SqlQuery<graphDBContext>(SqlStatement.ToString()).ToList();
This translates into SELECT id,Temp FROM graph_update
And the result gives me
id = 1, temp = 20
id = 2 temp = 30
How do I get all these values????
I'm too use to:
foreach(var item in result)
{
item.id = id;
item.temp = temp;
}
But it won't let me.
EDIT:
Sorry but I'm not sure what you mean. Here is my debugger
Try to use foreach like this if theres no error return
foreach(var v in result)
{
String v0 = v[0].ToString();
String v1 = v[1].ToString();
}
Assuming you have EF > 6, then the ctx.Database.SqlQuery, according to the method documentation:
Creates a raw SQL query that will return elements of the given generic type.
The type can be any type that has properties that match the names of the columns returned from the query, or can be a simple primitive type. The type does not have to be an entity type. The results of this query are never tracked by the context even if the type of object returned is an entity type.
With that in mind you can do something like this:
public class GraphUpdateResult
{
public int Id {get; set;}
public decimal Temp {get; set;}
}
Then in your current method:
var result = ctx.Database.SqlQuery<GraphUpdateResult>SqlStatement.ToString()).ToList();
foreach (var graphResult in result)
{
Console.WriteLine(graphResult.Id);
Console.WriteLine(graphResult.Temp);
}
You can add more columns to the GraphUpdateResult class for EF to bind to, even if in some queries you don't specify them in the select statement.
I hope this helps.
foreach(var item in result)
{
var id = item.id;
var temp = item.temp;
}
in your code above, you are trying to assign the values to the item, instead of retrieving.
You can use a ORM-Mapper like
https://stormy.codeplex.com/SourceControl/latest#Stormy.cs
It is a very light Mapper and you can look how it works.
It maps the reader Data to the Object data:
public class CatMapper : ISelectable<Cat>
{
public Cat ApplySelect(IDataReader reader)
{
return new Cat()
{
Name = reader["name"].ToString(),
Weight = (float)reader["weight"]
};
}
}

Dynamic casting to a generic type

I'm trying to get to the Cases.Values property of System.Activities.Statements.Switch object. The problem is that I cannot cast Activity object at runtime to Switch<> type (which derives from it).
var switchType = activity.GetType();
bool isSwitch = (switchType.IsGenericType && switchType.GetGenericTypeDefinition() == typeof(Switch<>));
if (isSwitch)
{
Type[] genericArgumentTypes = switchType.GetGenericArguments();
if (genericArgumentTypes.Length > 0)
{
var switchStatement = (Switch<genericArgumentTypes[0]>) activity; //that's incorrect
foreach (var aCase in switchStatement.Cases.Values)
{
ProcessActivity(aCase, dataSets, context);
}
}
}
Also,
dynamic switchStatement = activity;
foreach (var aCase in switchStatement.Cases.Values)
{
ProcessActivity(aCase, dataSets, context);
}
throws an error, that the property is not there, while debugger is showing it's not true. The T is irrelevant for me - I need only the Cases collection.
EDIT
Actually, I've found even cleaner solution, than the one I set as an answer.
dynamic switchStatement = activity;
var cases = switchStatement.Cases as IEnumerable;
if (cases != null)
{
foreach (dynamic aCase in cases)
{
ProcessActivity(aCase.Value);
}
}
You can't.
But instead of your loop, put:
var process = typeof(CurrentHelperClass).GetMethod("ProcessSwitch`1").MakeGenericMethod(typeof(genericArgumentTypes[0]));
process.Invoke(null,new object[]{activity});
and define a new method in the same class:
static void ProcessSwitch<T>(Switch<T> switchStatement)
{
foreach (var aCase in switchStatement.Cases.Values)
{
ProcessActivity(aCase, dataSets, context);
}
}
var switchType = activity.GetType();
var prop = switchType.GetProperty("Cases", System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.Instance); //move it outside of the method and use the same property for every time you call the method since it's performance expansive.
bool isSwitch = (switchType.IsGenericType && switchType.GetGenericTypeDefinition() == typeof(Switch<>));
if (isSwitch)
{
IEnumerable dictionary = prop.GetValue(activity,null) as IDictionary;
foreach (var item in dictionary.Values)
{
ProcessActivity(item, dataSets, context);
}
}

cast to a variable type

Is it possible to cast from a Dynamic or an Object to a variable type? The target variable type is one generic class, only the specific data type varies.
I'm looking for abstract solution, but the situation is this: I want a single Linq2SQL command for different Entities - I can GetProperty + GetValue of the EntityFramework Context, but then it must be casted to some exact types, but these come from variable input - names of DB tables.
Example of what I have:
Type NewType = typeof(System.Data.Objects.ObjectSet<>);
NewType.MakeGenericType(new Type[] {"...some type here that's variable accordint to user input - like Person, Address, Contact, ..."});
Object MyObject = Context.GetType().GetProperty("the same variable like above - Person, Address,...", BindingFlags.Public | BindingFlags.Instance).GetValue(Context, null); // this is EntityFramework Context
Example of what I need but don't know how to do it:
NewType CastedObject = (NewType) MyObject;
// or
NewType CastedObject = Convert.ChangeType(MyObject, NewType);
// or
NewType CastedObject = MyObject as NewType;
so I could do this:
(from x in CastedObject where x.ID == ID select x).FirstOrDefault();
For those, who are familiar with PHP, I'm trying to do this:
(from x in Context.$tablename where x.ID == ID select x).FirstOrDefault();
Since NewType is a runtime type, how could you have a variable of compile-time type NewType? The compiler must know the "declared" type of all variables. So what you want is not possible.
Something you can do is cast MyObject to dynamic. Then stuff like foreach (var x in CastedToDynamic) would compile (but no compile-time type checking).
You can't use LINQ on a dynamic expression, though. You will have to rewrite like:
dynamic found = null;
foreach (var x in CastedToDynamic)
{
if (x.ID == ID)
{
found = x;
break;
}
}
Note: Which overload of == to use will be decided at run-time. So even if ID is a (boxed) System.Guid, say, the == will (unbox and) call the overload of == defined inside that struct. So this works.
Something like this might get at what you are looking at (relies heavily on reflection)
List<dynamic> mylist = new List<dynamic>();
dynamic data = new ExpandoObject();
data.Foo = "foo";
data.ID = 1;
mylist.Add(data);
data = new ExpandoObject();
data.Foo = "foobar";
data.ID = 2;
mylist.Add(data);
data = new ExpandoObject();
data.Foo = "foobar2";
data.ID = 2;
mylist.Add(data);
data = new ExpandoObject();
data.Foo = "foobar2";
data.ID = 3;
mylist.Add(data);
int idiminterestedin = 2;
var dynamicselected = mylist.Select(d=>((IDictionary<string,object>)d)).Where(d=>
{
object id;
if (d.TryGetValue("ID",out id))
{
return (id is int) && (int)id == idiminterestedin;
}
return false;
});
foreach (var v in dynamicselected)
{
Console.WriteLine(v["Foo"]);
}
Console.ReadLine();
Though I'd probably skip the ExpandoObject and go straight for a dictionary:
Dictionary<string, object> data = new Dictionary<string, object>();
data["Foo"] = "foo";
data["ID"] = 1;
And then make a generic extension function(s):
static class ExptensionFunction
{
static T GetValueAs<T>(this Dictionary<string, object> obj, string key)
{
return (T)obj[key];
}
static bool TryGetValueAs<T>(this Dictionary<string, object> d, string key, out T value)
{
object id;
if (d.TryGetValue(key, out id))
{
if (id is T)
{
value = (T)id;
return true;
}
}
value = default(T);
return false;
}
static IEnumerable<Dictionary<string, object>> GetValuesWithKey<T>(this List<Dictionary<string, object>> list, string key, T value)
{
return list.Where(d =>
{
T id;
if (d.TryGetValueAs<T>(key, out id))
{
return id.Equals(value);
}
return false;
});
}
}
Inspired by this:
Creating an anonymous type dynamically?
and
Add property to anonymous type after creation

C#. Set a member object value using reflection

I need your help with the following code below. Basically I have a class called "Job" which has some public fields. I'm passing to my method "ApplyFilter" two parameters "job_in" and "job_filters". First parameter contains actual data, and the second one has instructions (if any). I need to iterate through "job_in" object, read it's data, apply any instructions by reading "job_filters", modify data (if needed) and return it in a new "job_out" object. Everything works fine till i need to store my data in "job_out" object:
public class Job
{
public string job_id = "";
public string description = "";
public string address = "";
public string details = "";
}
...
private Job ApplyFilters(Job job_in, Job job_filters)
{
Type type = typeof(Job);
Job job_out = new Job();
FieldInfo[] fields = type.GetFields();
// iterate through all fields of Job class
for (int i = 0; i < fields.Length; i++)
{
List<string> filterslist = new List<string>();
string filters = (string)fields[i].GetValue(job_filters);
// if job_filters contaisn magic word "$" for the field, then do something with a field, otherwise just copy it to job_out object
if (filters.Contains("$"))
{
filters = filters.Substring(filters.IndexOf("$") + 1, filters.Length - filters.IndexOf("$") - 1);
// MessageBox.Show(filters);
// do sothing useful...
}
else
{
// this is my current field value
var str_value = fields[i].GetValue(job_in);
// this is my current filed name
var field_name = fields[i].Name;
// I got stuck here :(
// I need to save (copy) data "str_value" from job_in.field_name to job_out.field_name
// HELP!!!
}
}
return job_out;
}
Please help. I've seen a few samples by using properties, but i'm pretty sure it is possible to do the same with fields as well. Thanks!
Try this
public static void MapAllFields(object source, object dst)
{
System.Reflection.FieldInfo[] ps = source.GetType().GetFields();
foreach (var item in ps)
{
var o = item.GetValue(source);
var p = dst.GetType().GetField(item.Name);
if (p != null)
{
Type t = Nullable.GetUnderlyingType(p.FieldType) ?? p.FieldType;
object safeValue = (o == null) ? null : Convert.ChangeType(o, t);
p.SetValue(dst, safeValue);
}
}
}
fields[i].SetValue(job_out, str_value);

Categories