Trying to string.Join an IList and outputting the results to console - linq

Using "string.Join(",", test);" works but for some reason I get an output of:
"Ilistprac.Location, Ilistprac.Location, Ilistprac.Location"
I tried ToString, Convert.ToString, etc and I still get that output.
All the IList interfaces are implemented with the IEnurmerable too (just not listed here unless someone wants me to).
class IList2
{
static void Main(string[] args)
{
string sSite = "test";
string sBldg = "test32";
string sSite1 = "test";
string sSite2 = "test";
Locations test = new Locations();
Location loc = new Location();
test.Add(sSite, sBldg)
test.Add(sSite1)
test.Add(sSite2)
string printitout = string.Join(",", test); //having issues outputting whats on the list
}
}
string printitout = string.Join(",", test.ToArray<Location>);
public class Location
{
public Location()
{
}
private string _site = string.Empty;
public string Site
{
get { return _site; }
set { _site = value; }
}
}
public class Locations : IList<Location>
{
List<Location> _locs = new List<Location>();
public Locations() { }
public void Add(string sSite)
{
Location loc = new Location();
loc.Site = sSite;
loc.Bldg = sBldg;
_locs.Add(loc);
}
private string _bldg = string.Empty;
public string Bldg
{
get { return _bldg; }
set { _bldg = value; }
}
}

You need to supply a useful ToString implementation for Location as Join is calling that for each element. The default implementation will just return the name of the type. See documentation.
So if you have a type like
class SomeType
{
public string FirstName { get; private set; }
public string LastName { get; private set; }
public SomeType(string first, string last)
{
FirstName = first;
LastName = last;
}
public override string ToString()
{
return string.Format("{0}, {1}", LastName, FirstName);
}
}
You need to specify how that should be represented as a string. If you do that, you can use string.Join like this to produce the output below.
var names = new List<SomeType> {
new SomeType("Homer", "Simpson"),
new SomeType("Marge", "Simpson")
};
Console.WriteLine(string.Join("\n", names));
Output:
Simpson, Homer
Simpson, Marge

You have to override ToString() inc your Location class to provide some meaningful output if you want to keep your current approach, E.g.:
public override string ToString()
{
return Site;
}

Related

How to send complex objects in GET to WEB API 2

Let's say that you have the following code
public class MyClass {
public double Latitude {get; set;}
public double Longitude {get; set;}
}
public class Criteria
{
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public MyClass MyProp {get; set;}
}
[HttpGet]
public Criteria Get([FromUri] Criteria c)
{
return c;
}
I'd like to know if someone is aware of a library that could transform any object into query string that is understood by a WEB API 2 Controller.
Here is an example of what I'd like
SerializeToQueryString(new Criteria{StartDate=DateTime.Today, EndDate = DateTime.Today.AddDays(1), MyProp = new MyProp{Latitude=1, Longitude=3}});
=> "startDate=2015-10-13&endDate=2015-10-14&myProp.latitude=1&myProp.longitude=3"
A full example with httpClient might look like :
new HttpClient("http://localhost").GetAsync("/tmp?"+SerializeToQueryString(new Criteria{StartDate=DateTime.Today, EndDate = DateTime.Today.AddDays(1), MyProp = new MyProp{Latitude=1, Longitude=3}})).Result;
At the moment, I use a version (taken from a question I do not find again, maybe How do I serialize an object into query-string format? ...).
The problem is that it is not working for anything else than simple properties.
For example, calling ToString on a Date will not give something that is parseable by WEB API 2 controller...
private string SerializeToQueryString<T>(T aObject)
{
var query = HttpUtility.ParseQueryString(string.Empty);
var fields = typeof(T).GetProperties();
foreach (var field in fields)
{
string key = field.Name;
var value = field.GetValue(aObject);
if (value != null)
query[key] = value.ToString();
}
return query.ToString();
}
"Transform any object to a query string" seems to imply there's a standard format for this, and there just isn't. So you would need to pick one or roll your own. JSON seems like the obvious choice due to the availability of great libraries.
Since it seems no one has dealt with the problem before, here is the solution I use in my project :
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Globalization;
using System.Linq;
using System.Web;
namespace App
{
public class QueryStringSerializer
{
public static string SerializeToQueryString(object aObject)
{
return SerializeToQueryString(aObject, "").ToString();
}
private static NameValueCollection SerializeToQueryString(object aObject, string prefix)
{
//!\ doing this to get back a HttpValueCollection which is an internal class
//we want a HttpValueCollection because toString on this class is what we want in the public method
//cf http://stackoverflow.com/a/17096289/1545567
var query = HttpUtility.ParseQueryString(String.Empty);
var fields = aObject.GetType().GetProperties();
foreach (var field in fields)
{
string key = string.IsNullOrEmpty(prefix) ? field.Name : prefix + "." + field.Name;
var value = field.GetValue(aObject);
if (value != null)
{
var propertyType = GetUnderlyingPropertyType(field.PropertyType);
if (IsSupportedType(propertyType))
{
query.Add(key, ToString(value));
}
else if (value is IEnumerable)
{
var enumerableValue = (IEnumerable) value;
foreach (var enumerableValueElement in enumerableValue)
{
if (IsSupportedType(GetUnderlyingPropertyType(enumerableValueElement.GetType())))
{
query.Add(key, ToString(enumerableValueElement));
}
else
{
//it seems that WEB API 2 Controllers are unable to deserialize collections of complex objects...
throw new Exception("can not use IEnumerable<T> where T is a class because it is not understood server side");
}
}
}
else
{
var subquery = SerializeToQueryString(value, key);
query.Add(subquery);
}
}
}
return query;
}
private static Type GetUnderlyingPropertyType(Type propType)
{
var nullablePropertyType = Nullable.GetUnderlyingType(propType);
return nullablePropertyType ?? propType;
}
private static bool IsSupportedType(Type propertyType)
{
return SUPPORTED_TYPES.Contains(propertyType) || propertyType.IsEnum;
}
private static readonly Type[] SUPPORTED_TYPES = new[]
{
typeof(DateTime),
typeof(string),
typeof(int),
typeof(long),
typeof(float),
typeof(double)
};
private static string ToString(object value)
{
if (value is DateTime)
{
var dateValue = (DateTime) value;
if (dateValue.Hour == 0 && dateValue.Minute == 0 && dateValue.Second == 0)
{
return dateValue.ToString("yyyy-MM-dd");
}
else
{
return dateValue.ToString("yyyy-MM-dd HH:mm:ss");
}
}
else if (value is float)
{
return ((float) value).ToString(CultureInfo.InvariantCulture);
}
else if (value is double)
{
return ((double)value).ToString(CultureInfo.InvariantCulture);
}
else /*int, long, string, ENUM*/
{
return value.ToString();
}
}
}
}
Here is the unit test to demonstrate :
using System;
using System.Collections.Generic;
using System.Globalization;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Framework.WebApi.Core.Tests
{
[TestClass]
public class QueryStringSerializerTest
{
public class EasyObject
{
public string MyString { get; set; }
public int? MyInt { get; set; }
public long? MyLong { get; set; }
public float? MyFloat { get; set; }
public double? MyDouble { get; set; }
}
[TestMethod]
public void TestEasyObject()
{
var queryString = QueryStringSerializer.SerializeToQueryString(new EasyObject(){MyString = "string", MyInt = 1, MyLong = 1L, MyFloat = 1.5F, MyDouble = 1.4});
Assert.IsTrue(queryString.Contains("MyString=string"));
Assert.IsTrue(queryString.Contains("MyInt=1"));
Assert.IsTrue(queryString.Contains("MyLong=1"));
Assert.IsTrue(queryString.Contains("MyFloat=1.5"));
Assert.IsTrue(queryString.Contains("MyDouble=1.4"));
}
[TestMethod]
public void TestEasyObjectNullable()
{
var queryString = QueryStringSerializer.SerializeToQueryString(new EasyObject() { });
Assert.IsTrue(queryString == "");
}
[TestMethod]
public void TestUrlEncoding()
{
var queryString = QueryStringSerializer.SerializeToQueryString(new EasyObject() { MyString = "&=/;+" });
Assert.IsTrue(queryString.Contains("MyString=%26%3d%2f%3b%2b"));
}
public class DateObject
{
public DateTime MyDate { get; set; }
}
[TestMethod]
public void TestDate()
{
var d = DateTime.ParseExact("2010-10-13", "yyyy-MM-dd", CultureInfo.InvariantCulture);
var queryString = QueryStringSerializer.SerializeToQueryString(new DateObject() { MyDate = d });
Assert.IsTrue(queryString.Contains("MyDate=2010-10-13"));
}
[TestMethod]
public void TestDateTime()
{
var d = DateTime.ParseExact("2010-10-13 20:00", "yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture);
var queryString = QueryStringSerializer.SerializeToQueryString(new DateObject() { MyDate = d });
Assert.IsTrue(queryString.Contains("MyDate=2010-10-13+20%3a00%3a00"));
}
public class InnerComplexObject
{
public double Lat { get; set; }
public double Lon { get; set; }
}
public class ComplexObject
{
public InnerComplexObject Inner { get; set; }
}
[TestMethod]
public void TestComplexObject()
{
var queryString = QueryStringSerializer.SerializeToQueryString(new ComplexObject() { Inner = new InnerComplexObject() {Lat = 50, Lon = 2} });
Assert.IsTrue(queryString.Contains("Inner.Lat=50"));
Assert.IsTrue(queryString.Contains("Inner.Lon=2"));
}
public class EnumerableObject
{
public IEnumerable<int> InnerInts { get; set; }
}
[TestMethod]
public void TestEnumerableObject()
{
var queryString = QueryStringSerializer.SerializeToQueryString(new EnumerableObject() {
InnerInts = new[] { 1,2 }
});
Assert.IsTrue(queryString.Contains("InnerInts=1"));
Assert.IsTrue(queryString.Contains("InnerInts=2"));
}
public class ComplexEnumerableObject
{
public IEnumerable<InnerComplexObject> Inners { get; set; }
}
[TestMethod]
public void TestComplexEnumerableObject()
{
try
{
QueryStringSerializer.SerializeToQueryString(new ComplexEnumerableObject()
{
Inners = new[]
{
new InnerComplexObject() {Lat = 50, Lon = 2},
new InnerComplexObject() {Lat = 51, Lon = 3},
}
});
Assert.Fail("we should refuse something that will not be understand by the server");
}
catch (Exception e)
{
Assert.AreEqual("can not use IEnumerable<T> where T is a class because it is not understood server side", e.Message);
}
}
public enum TheEnum : int
{
One = 1,
Two = 2
}
public class EnumObject
{
public TheEnum? MyEnum { get; set; }
}
[TestMethod]
public void TestEnum()
{
var queryString = QueryStringSerializer.SerializeToQueryString(new EnumObject() { MyEnum = TheEnum.Two});
Assert.IsTrue(queryString.Contains("MyEnum=Two"));
}
}
}
I'd like to thank all the participants even if this is not something that you should usually do in a Q&A format :)

Setting session variables in a class is setting all of them, not just one

I have been researching a way to set session variables for my Web App to store the logged in user's info. I have made a lot of progress, being a novice, but I am stumped as to why setting the variables will set all of them and not just the one specified. Can someone point out my mistake(s), please? Thank you!!
using System;
using System.DirectoryServices;
using System.Security.Principal;
using System.Web;
using System.Web.UI;
namespace ITHD
{
public class Common : Page
{
public static void GetLoggedInUserProperties()
{
string gLoginId = ExtractUserName(WindowsIdentity.GetCurrent().Name);
SessionManager.LoginId = gLoginId;
VerifyInAD(gLoginId);
}
private static void VerifyInAD(string sUser)
{
try
{
string userName = ExtractUserName(sUser);
DirectorySearcher search = new DirectorySearcher();
search.Filter = String.Format("(SAMAccountName={0})", userName);
search.PropertiesToLoad.Add("cn");
search.PropertiesToLoad.Add("MemberOf");
search.PropertiesToLoad.Add("givenname");
search.PropertiesToLoad.Add("sn");
search.PropertiesToLoad.Add("phone");
search.PropertiesToLoad.Add("title");
SearchResult result = search.FindOne();
//SessionManager.CanEdit = "False";
SessionManager.UserName = string.Empty;
if (result != null)
{
SessionManager.UserName = string.Format("{0}", result.Properties["cn"][0].ToString());
bool admin = checkGroup("Helpdesk Agents");
if (admin == true)
{
SessionManager.HDAgent = "True";
}
}
search.Dispose();
}
catch (Exception ex)
{
SessionManager.UserName = "Guest";
}
}
public static string ExtractUserName(string path)
{
string[] userPath = path.Split(new char[] { '\\' });
return userPath[userPath.Length - 1];
}
public static bool checkGroup(string group)
{
WindowsIdentity identity = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(identity);
return principal.IsInRole(group);
}
}
public static class SessionManager
{
private const string sLoginId = "";
public static string LoginId
{
get
{
if (null != HttpContext.Current.Session[sLoginId])
return HttpContext.Current.Session[sLoginId] as string;
else
return "Guest";
}
set
{
HttpContext.Current.Session[sLoginId] = value;
}
}
private const string sUserName = "";
public static string UserName
{
get
{
if (null != HttpContext.Current.Session[sUserName])
return HttpContext.Current.Session[sUserName] as string;
else
return "Guest";
}
set
{
HttpContext.Current.Session[sUserName] = value;
}
}
private const string sHDAgent = "";
public static string HDAgent
{
get
{
if (null != HttpContext.Current.Session[sHDAgent])
return HttpContext.Current.Session[sHDAgent] as string;
else
return "False";
}
set
{
HttpContext.Current.Session[sHDAgent] = value;
}
}
}
}
I don't think you are setting your session keys correctly. In your static class you have a property setter that is essentially session Session[""]=Some Value for all members. You do not need to set the key to the name of the private member in .net 3.5 you do not even need the private member. You could also just stuff the whole session object in and not worry about each member.
Then just access a Current instantiator of the properties as in
MySession.Current.UserName="guest";
public class MySession
{
private const string _SessionName = "__MY_SESSION__";
//--------------------------------------------------------------------------------------------
private MySession(){}
//--------------------------------------------------------------------------------------------
public static MySession Current
{
get
{
MySession session =
(MySession)HttpContext.Current.Session[_SessionName];
if (session == null)
{
session = new MySession();
session.Property1 = new Property1();
session.Property2 = new Property2();
session.UserName = "";
HttpContext.Current.Session[_SessionName] = session;
}
return session;
}
}
public string UserName { get; set; }
public Property1 Property1 { get; set; }
public Property2 Property2 { get; set; }
}

How to store multiple data in isolated storage setting in wp7?

I want to store multiple name in Isolated storage.And i use this code for store multopple storage
if (!setting.Contains("CityDetail"))
{
setting.Add("CityDetail", cityname);
}
else
{
setting["CityDetail"] = cityname;
}
setting.Save();
But it gives only last added value,h=So how can i fetch all the data base value?
You can use these function to store your objects in phoneapplication state
public static void SaveState(string key, object value)
{
if (phoneApplicationPage.State.ContainsKey(key))
{
phoneApplicationPage.State.Remove(key);
}
phoneApplicationPage.State.Add(key, value);
}
public static object LoadState(this PhoneApplicationPage phoneApplicationPage, string key)
{
if (phoneApplicationPage.State.ContainsKey(key))
{
return phoneApplicationPage.State[key];
}
return null;
}
Edit-Using isolatedsettings
public void SaveCompositeObject()
{
var settings = IsolatedStorageSettings.ApplicationSettings;
Person person= new City { Name = "Alex", Age= "21" };
settings.Add("person", person);
}
public class Person
{
public string Name
{
get;
set;
}
public string Age
{
get;
set;
}
}
retrieving data
Person person1;
settings.TryGetValue<Person>("person", out person11);

Translating expression tree from a type to another type with complex mappings

inspired by this answer I'm trying to map a property on a model class to an expression based on the actual entity.
These are the two classes involved:
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Id { get; set; }
public DateTime? BirthDate { get; set; }
public int CustomerTypeId { get; set; }
}
public class CustomerModel
{
...
public bool HasEvenId { get; set; }
}
An example of a possible expression I'd like to convert is:
Expression<Func<CustomerModel, bool>> from = model => model.HasEvenId;
Expression<Func<Customer, bool>> to = entity => ((entity.Id % 2) == 0);
The problem is that I have to expose an OData endpoint via ASP.NET WebAPI but I need to make some operations on the entities before I can them, hence the need of a model class and the need to translate the expression based on the model that I could receive as an OData query in an expression based on the entity, that I would use to query EF4.
This is where I got so far:
private static readonly Dictionary<Expression, Expression> Mappings = GetMappings();
private static Dictionary<Expression, Expression> GetMappings()
{
var mappings = new Dictionary<Expression, Expression>();
var mapping = GetMappingFor((CustomerModel model) => model.HasEvenId, (Customer customer) => (customer.Id%2) == 0);
mappings.Add(mapping.Item1, mapping.Item2);
return mappings;
}
private static Tuple<Expression, Expression> GetMappingFor<TFrom, TTo, TValue>(Expression<Func<TFrom, TValue>> fromExpression, Expression<Func<TTo, TValue>> toExpression)
{
MemberExpression fromMemberExpression = (MemberExpression) fromExpression.Body;
return Tuple.Create<Expression, Expression>(fromMemberExpression, toExpression);
}
public static Expression<Func<TTo, bool>> Translate<TFrom, TTo>(Expression<Func<TFrom, bool>> expression, Dictionary<Expression, Expression> mappings = null)
{
if (expression == null)
return null;
string parameterName = expression.Parameters[0].Name;
parameterName = string.IsNullOrWhiteSpace(parameterName) ? "p" : parameterName;
var param = Expression.Parameter(typeof(TTo), parameterName);
var subst = new Dictionary<Expression, Expression> { { expression.Parameters[0], param } };
ParameterChangeVisitor parameterChange = new ParameterChangeVisitor(parameterName);
if (mappings != null)
foreach (var mapp in mappings)
subst.Add(mapp.Key, parameterChange.Visit(mapp.Value));
var visitor = new TypeChangeVisitor(typeof(TFrom), typeof(TTo), subst);
return Expression.Lambda<Func<TTo, bool>>(visitor.Visit(expression.Body), param);
}
public IQueryable<CustomerModel> Get()
{
var filterExtractor = new ODataFilterExtractor<CustomerModel>();
Expression<Func<CustomerModel, bool>> expression = filterExtractor.Extract(Request);
Expression<Func<Customer, bool>> translatedExpression = Translate<CustomerModel, Customer>(expression, Mappings);
IQueryable<Customer> query = _context.Customers;
if (translatedExpression != null)
query = query.Where(translatedExpression);
var finalQuery = from item in query.AsEnumerable()
select new CustomerModel()
{
FirstName = item.FirstName,
LastName = item.LastName,
Id = item.Id,
BirthDate = item.BirthDate,
CustomerTypeId = item.CustomerTypeId,
HasEvenId = (item.Id % 2 ) == 0
};
return finalQuery.AsQueryable();
}
where:
ODataFilterExtractor is a class that extract the $filter expression from the RequestMessage we receive;
ParameterChangeVisitor just changes all the ParameterExpression to a new one having the provided string as parameter name;
In addition, I changed the VisitMember method of the answer linked above in this way:
protected override Expression VisitMember(MemberExpression node)
{
// if we see x.Name on the old type, substitute for new type
if (node.Member.DeclaringType == _from)
{
MemberInfo toMember = _to.GetMember(node.Member.Name, node.Member.MemberType, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).SingleOrDefault();
if (toMember != null)
{
return Expression.MakeMemberAccess(Visit(node.Expression), toMember);
}
else
{
if (_substitutions.Select(kvp => kvp.Key).OfType<MemberExpression>().Any(me => me.Member.Equals(node.Member)))
{
MemberExpression key = _substitutions.Select(kvp => kvp.Key).OfType<MemberExpression>().Single(me => me.Member.Equals(node.Member));
Expression value = _substitutions[key];
// What to return here?
return Expression.Invoke(value);
}
}
}
return base.VisitMember(node);
}
Thanks for you help.
I took the liberty of modifying your code just a hair but this does the trick,
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Id { get; set; }
public DateTime? BirthDate { get; set; }
public int CustomerTypeId { get; set; }
}
public class CustomerModel
{
public string FullName { get; set; }
public bool HasEvenId { get; set; }
}
sealed class AToBConverter<TA, TB> : ExpressionVisitor
{
private readonly Dictionary<ParameterExpression, ParameterExpression> _parameters = new Dictionary<ParameterExpression, ParameterExpression>();
private readonly Dictionary<MemberInfo, LambdaExpression> _mappings;
protected override Expression VisitParameter(ParameterExpression node)
{
if (node.Type == typeof(TA))
{
ParameterExpression parameter;
if (!this._parameters.TryGetValue(node, out parameter))
{
this._parameters.Add(node, parameter = Expression.Parameter(typeof(TB), node.Name));
}
return parameter;
}
return node;
}
protected override Expression VisitMember(MemberExpression node)
{
if (node.Expression == null || node.Expression.Type != typeof(TA))
{
return base.VisitMember(node);
}
Expression expression = this.Visit(node.Expression);
if (expression.Type != typeof(TB))
{
throw new Exception("Whoops");
}
LambdaExpression lambdaExpression;
if (this._mappings.TryGetValue(node.Member, out lambdaExpression))
{
return new SimpleExpressionReplacer(lambdaExpression.Parameters.Single(), expression).Visit(lambdaExpression.Body);
}
return Expression.Property(
expression,
node.Member.Name
);
}
protected override Expression VisitLambda<T>(Expression<T> node)
{
return Expression.Lambda(
this.Visit(node.Body),
node.Parameters.Select(this.Visit).Cast<ParameterExpression>()
);
}
public AToBConverter(Dictionary<MemberInfo, LambdaExpression> mappings)
{
this._mappings = mappings;
}
}
sealed class SimpleExpressionReplacer : ExpressionVisitor
{
private readonly Expression _replacement;
private readonly Expression _toFind;
public override Expression Visit(Expression node)
{
return node == this._toFind ? this._replacement : base.Visit(node);
}
public SimpleExpressionReplacer(Expression toFind, Expression replacement)
{
this._toFind = toFind;
this._replacement = replacement;
}
}
class Program
{
private static Dictionary<MemberInfo, LambdaExpression> GetMappings()
{
var mappings = new Dictionary<MemberInfo, LambdaExpression>();
var mapping = GetMappingFor(model => model.HasEvenId, customer => (customer.Id % 2) == 0);
mappings.Add(mapping.Item1, mapping.Item2);
mapping = GetMappingFor(model => model.FullName, customer => customer.FirstName + " " + customer.LastName);
mappings.Add(mapping.Item1, mapping.Item2);
return mappings;
}
private static Tuple<MemberInfo, LambdaExpression> GetMappingFor<TValue>(Expression<Func<CustomerModel, TValue>> fromExpression, Expression<Func<Customer, TValue>> toExpression)
{
return Tuple.Create(((MemberExpression)fromExpression.Body).Member, (LambdaExpression)toExpression);
}
static void Main()
{
Expression<Func<CustomerModel, bool>> source = model => model.HasEvenId && model.FullName == "John Smith";
Expression<Func<Customer, bool>> desiredResult = model => (model.Id % 2) == 0 && (model.FirstName + " " + model.LastName) == "John Smith";
Expression output = new AToBConverter<CustomerModel, Customer>(GetMappings()).Visit(source);
Console.WriteLine("The two expressions do {0}match.", desiredResult.ToString() == output.ToString() ? null : "not ");
Console.ReadLine();
}
}
Another solution would be to use AutoMapper to map complex types and modify the resulting expression query with an ExpressionTransformer before it gets executed. I will try to explain with a complete sample:
Model classes
Some POCO classes just for holding data.
public enum CostUnitType
{
None = 0,
StockUnit = 1,
MachineUnit = 2,
MaintenanceUnit = 3
}
public class CostUnit
{
public string CostUnitId { get; set; }
public string WorkplaceId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public CostUnitType Type { get; set; }
public override string ToString()
{
return CostUnitId + " " + Name + " " + Type;
}
}
public class StockUnit
{
public string Id { get; set; }
public string Name { get; set; }
}
public class MachineUnit
{
public string Id { get; set; }
public string Name { get; set; }
}
public class MaintenanceUnit
{
public string Id { get; set; }
public string Name { get; set; }
}
The ExpressionTransformer class
Most of the time, using the Mapper static class is fine, but sometimes you need to map the same types with different configurations, so you need to explicitly use an IMappingEngine like this:
var configuration = new ConfigurationStore(new TypeMapFactory(), MapperRegistry.Mappers);
var engine = new MappingEngine(configuration);
The way to create a MappingEngine is not obvious at all. I had to dig in the source code to find how it was done.
public static class ExpressionTransformer
{
private static readonly MappingEngine Mapper;
/// <summary>
/// Initializes the <see cref="ExpressionTransformer"/> class.
/// Creates an instance of AutoMapper. Initializes mappings.
/// </summary>
static ExpressionTransformer()
{
ConfigurationStore configurationStore = new ConfigurationStore(new TypeMapFactory(), MapperRegistry.Mappers);
// Create mapping
// Maps Id from StockUnit to CostUnitId from CostUnit
configurationStore.CreateMap<StockUnit, CostUnit>()
.ForMember(m => m.CostUnitId, opt => opt.MapFrom(src => src.Id));
// Maps Id from MachineUnit to CostUnitId from CostUnit
configurationStore.CreateMap<MachineUnit, CostUnit>()
.ForMember(m => m.CostUnitId, opt => opt.MapFrom(src => src.Id));
// Maps Id from MaintenanceUnit to CostUnitId from CostUnit
configurationStore.CreateMap<MaintenanceUnit, CostUnit>()
.ForMember(m => m.CostUnitId, opt => opt.MapFrom(src => src.Id));
// Create instance of AutoMapper
Mapper = new MappingEngine(configurationStore);
}
public static Expression<Func<TDestination, bool>> Tranform<TSource, TDestination>(Expression<Func<TSource, bool>> sourceExpression)
{
// Resolve mappings by AutoMapper for given types.
var map = Mapper.ConfigurationProvider.FindTypeMapFor(typeof(TSource), typeof(TDestination));
if (map == null)
{
throw new AutoMapperMappingException(string.Format("No Mapping found for {0} --> {1}.", typeof(TSource).Name, typeof(TDestination).Name));
}
// Transform from TSource to TDestination with specified mappings
var visitor = new ParameterTypeVisitor<TSource, TDestination>(sourceExpression, map.GetPropertyMaps());
var expression = visitor.Transform();
return expression;
}
private class ParameterTypeVisitor<TSource, TDestination> : ExpressionVisitor
{
private readonly Dictionary<string, ParameterExpression> _parameters;
private readonly Expression<Func<TSource, bool>> _expression;
private readonly IEnumerable<PropertyMap> _maps;
public ParameterTypeVisitor(Expression<Func<TSource, bool>> expression, IEnumerable<PropertyMap> maps)
{
_parameters = expression.Parameters
.ToDictionary(p => p.Name, p => Expression.Parameter(typeof(TDestination), p.Name));
_expression = expression;
_maps = maps;
}
public Expression<Func<TDestination, bool>> Transform()
{
return (Expression<Func<TDestination, bool>>) Visit(_expression);
}
protected override Expression VisitMember(MemberExpression node)
{
if (node.Member.DeclaringType == typeof(TSource))
{
var memberName = node.Member.Name;
var member = _maps.FirstOrDefault(p => typeof(TSource) == node.Expression.Type
&& p.SourceMember.Name == memberName);
if (member != null)
{
// Return Property from TDestination
var expression = Visit(node.Expression);
return Expression.MakeMemberAccess(expression, member.DestinationProperty.MemberInfo);
}
}
return base.VisitMember(node);
}
protected override Expression VisitParameter(ParameterExpression node)
{
var parameter = _parameters[node.Name];
return parameter;
}
protected override Expression VisitLambda<T>(Expression<T> node)
{
var expression = Visit(node.Body);
return Expression.Lambda(expression, _parameters.Select(x => x.Value));
}
}
}
Usage
To Convert an expression we just need to call Transform Method of ExpressionTransformer class
Expression<Func<StockUnit, bool>> stockQuery = unit => unit.Id == "0815" && unit.Name == "ABC";
// Call Transform<TSource, TDestination> method.
Expression<Func<CostUnit, bool>> costUnitQuery = ExpressionTransformer.Tranform<StockUnit, CostUnit>(stockQuery);
Result

data mode : read write with c# local database in wp7

I created a local db with helper app project. and deployed it from isolate storage to installation folder,i added to project directory with content build action by add existing item. my problem is that i want to insert data, but i don't know how to move the db file to isolate storage to insert and data must add to my .sdf file that is locate in my project directory also.
Souphia,
While learning to use WP, I wrote a simple application that tracked tasks.
One version of that app stored all task data in Sql on the phone.
You can read the post and download all the code for the app here:
http://www.ritzcovan.com/2012/02/building-a-simple-windows-phone-app-part-3/
But, here is some of the code from that project:
First we have the model class decorated with the appropriate attributes:
[Table]
public class Task : INotifyPropertyChanged, INotifyPropertyChanging
{
[Column(IsDbGenerated = false, IsPrimaryKey = true, CanBeNull = false)]
public string Id
{
get { return _id; }
set
{
NotifyPropertyChanging("Id");
_id = value;
NotifyPropertyChanging("Id");
}
}
[Column]
public string Name
{
get { return _name; }
set
{
NotifyPropertyChanging("Name");
_name = value;
NotifyPropertyChanged("Name");
}
}
[Column]
public string Category
{
get { return _category; }
set
{
NotifyPropertyChanging("Category");
_category = value;
NotifyPropertyChanged("Category");
}
}
[Column]
public DateTime? DueDate
{
get { return _dueDate; }
set
{
NotifyPropertyChanging("DueDate");
_dueDate = value;
NotifyPropertyChanged("DueDate");
}
}
[Column]
public DateTime? CreateDate
{
get { return _createDate; }
set
{
NotifyPropertyChanging("CreateDate");
_createDate = value;
NotifyPropertyChanged("CreateDate");
}
}
[Column]
public bool IsComplete
{
get { return _isComplete; }
set
{
NotifyPropertyChanging("IsComplete");
_isComplete = value;
NotifyPropertyChanged("IsComplete");
}
}
[Column(IsVersion = true)] private Binary _version;
private string _id;
private bool _isComplete;
private DateTime? _createDate;
private DateTime? _dueDate;
private string _name;
private string _category;
public event PropertyChangedEventHandler PropertyChanged;
public event PropertyChangingEventHandler PropertyChanging;
public void NotifyPropertyChanged(string property)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
public void NotifyPropertyChanging(string property)
{
if (PropertyChanging != null)
PropertyChanging(this, new PropertyChangingEventArgs(property));
}
}
In the constructor in app.xaml.cs, I have the following:
TaskMasterDataContext = new TaskMasterDataContext();
if (!TaskMasterDataContext.DatabaseExists())
{
TaskMasterDataContext.CreateDatabase();
DatabaseHelper.SetupDatabase(TaskMasterDataContext);
}
and here is the TaskMasterDataContext.cs code
public class TaskMasterDataContext : DataContext
{
public TaskMasterDataContext() : base("Data Source=isostore:/TaskMasterData.sdf")
{
}
public Table<Task> Tasks;
}
public static class DatabaseHelper
{
public static void SetupDatabase(TaskMasterDataContext dataContext)
{
string category = string.Empty;
var tasks = new List<Task>();
for (int i = 0; i < 20; i++)
{
tasks.Add(new Task()
{
Id = System.Guid.NewGuid().ToString(),
Category = GetCategoryString(i),
CreateDate = DateTime.Now,
DueDate = DateTime.Now.AddDays(new Random().Next(1, 30)),
IsComplete = false,
Name = String.Format("{0} Task # {1}", GetCategoryString(i), i)
});
}
dataContext.Tasks.InsertAllOnSubmit(tasks);
dataContext.SubmitChanges();
}
private static string GetCategoryString(int i)
{
if (i%2 == 0)
return "home";
if (i%3 == 0)
return "personal";
return "work";
}
}
The DatabaseHelper class is just there to populate the DB with some test data after its created.
I hope this helps.

Resources