I have a table storing datatypes of all the parameters and another table with the parameter values. When I use this in C# console app, how do I create a Type[] with the types present in the table?
Its not clear how you store the type in database. Assuming its the assembly qualified name (eg: System.String)
var types = new List<Type>();
foreach(var row in myTable.AsEnumerable())
{
var typeName = row.Field<string>("ColumnName");
types.Add(Type.GetType(typeName));
}
var array = types.ToArray();
Related
My JsonFX serialization code works, but the object that I'm serializing contains a list of polymorphic entities, and they're all deserialized as their base type and not their actual type.
Here's my serialization code:
public static string Serialize(System.Object obj)
{
StringBuilder builder = new StringBuilder();
using (TextWriter textWriter = new StringWriter(builder))
{
JsonWriter writer = new JsonWriter(textWriter);
writer.Write(obj);
return builder.ToString();
}
}
public static T Deserialize<T>(string json)
{
using (TextReader textReader = new StringReader(json))
{
var jsonReader = new JsonReader(textReader);
return jsonReader.Deserialize<T>();
}
}
As you can see it's pretty straightforward. I'm also not decorating my classes with any attributes or anything special to make them serializable. Besides the polymorphic problem, it all just seems to be working properly.
So how can I get my polymorphic types to deserialize properly?.
Thanks.
You need to turn on type hinting. Here's example code (this is relevant to JsonFx v1.4, may or may not work with your version):
StringBuilder result = new StringBuilder(string.Empty);
JsonWriterSettings settings = JsonDataWriter.CreateSettings(true);
settings.TypeHintName = "__type";
JsonWriter writer = new JsonWriter(result, settings);
writer.Write(obj);
return result.ToString();
This will add extra data to your JSON string which looks something like:
"__type": "MyNamespace.MyClass, MyAssembly",
Which means it finds out what derived type it is based on the class name. If you change your class name or namespace name, it won't work anymore. Worse, you can't deserialize from your old JSON text data anymore, unless you mass replace all occurrences of the old class name and replace it with the new.
So you have to be careful with it.
EDIT: Forgot to mention that you have to edit the source code of JsonFx for this to work.
In JsonReader.cs, find the ReadArray method:
Change:
object value = this.Read(arrayItemType, isArrayTypeAHint);
to:
object value = this.Read(null, false);
This will ensure that JsonFx will always attempt to figure out the type of each element in an array/list. If you want this to work for just single variables, well you'd need to do the changes on the appropriate code (haven't tried that).
Is there any way for ServiceStack's TypeSerializer to handle boxed objects with a bit more success? I'm imagining an extension/setting for it to encode types as necessary. For example if I were to serialize and deserialize:
Object x = Guid.NewGuid()
Object y = serializer.DeserializeFromString(serializer.SerializeToString(x))
I would end up with a boxed string in my new Object y, rather than a boxed Guid. It would be nice if it would know enough to give me a boxed Guid. Is it this possible? Has such a feature been considered for TypeSerializer?
There is no type information emitted on the wire for value types. You either need to specify the type information on the call site, e.g:
object y = x.ToJsv().FromJsv<Guid>();
Or the type information is on the type you're deserializing into, e.g:
public class Poco {
public Guid Id { get; set; }
}
var dto = new Poco { Id = Guid.NewGuid() }.ToJsv().FromJsv<Poco>();
Or you can use the dynamic API, e.g:
object id = JsonObject.Parse(new Poco { Id = Guid.NewGuid() }.ToJson())
.Get<Guid>("Id");
I'm trying to create a dynamic type in .Net.
I want to get a group of Key Value pairs from a DB table and create a new type of object that has a Property-Value relation.
Example:
If I have a row in the table that has a field that says "Licence Plate" and the other field says "STKOVFL". I want to create an object that has a Property called Licence_Plate, and returns the String "STKOVFL".
Is it possible with introspection?
Best Regards!
Here is an very simple example of what your trying to do.
public class ExampleD : DynamicObject
{
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null;
if (binder.Name == "Licence_Plate")
result = "STKOVFL";
return result != null;
}
}
Console.WriteLine(d.License_Plate);
Background
I am using a legacy database with all kinds of ugly corners. One bit is auditing. There is a table listing tablename/field combinations of fields that should have an audit trail. For example, if there is a row that has "WORKORDER" for the table name and "STATUS" for the fieldname, then I need to add row(s) to the auditing table whenever the Workorder.Status property changes in the application. I know the approach: NH events or interceptors, but I've got an issue to figure out before I get to that stage.
Question
What I need to know is how to get a list of key/value pairs for a single persistent class containing (a) the database field name and (b) the associated property name in the class. So for my example, I have a class called Workorder associated with a table called (no surprise) WORKORDER. I have a property on that Workorder class called CurrentStatus. The matching property in the WORKORDER table is STATUS. Notice the mismatch between the property name and table column name? I need to know the property name to access the before and after data for the audit. But I also need to know the backing column name so that I can query the stupid legacy "AuditTheseColumns" table.
What I've tried
in my application I change the Workorder.CurrentStatus from "TS" to "IP". I look in my audit tracking table and see that the WORKORDER.STATUS column is tracked. So after calling Session.SaveOrUpdate(workorder), I need to find the Workorder property associated with the STATUS column and do a Session.Save(auditRecord) telling it the old ("TS") and new ("IP") values.
As far as I can tell, you can get information about the class:
var fieldNames = new List<string>();
IClassMetadata classMetadata = SessionFactory(Resources.CityworksDatasource).GetClassMetadata(typeof(T));
int propertyCount = 0;
foreach (IType propertyType in classMetadata.PropertyTypes)
{
if (propertyType.IsComponentType)
{
var cp = (ComponentType)propertyType;
foreach (string propertyName in cp.PropertyNames)
{
fieldNames.Add(propertyName);
}
}
else if(!propertyType.IsCollectionType)
{
fieldNames.Add(classMetadata.PropertyNames[propertyCount + 1]);
}
propertyCount++;
}
And information about the table:
var columnNames = new List<string>();
PersistentClass mappingMeta = ConfigureCityworks().GetClassMapping(typeof(T));
foreach (Property property in mappingMeta.PropertyIterator)
{
foreach (Column selectable in property.ColumnIterator)
{
if (columnNames.Contains(selectable.Name)) continue;
columnNames.Add(selectable.Name);
}
}
But not at the same time. Any ideas? I'm at a loss where to look next.
How to get the database column / field names and class property names for an entity mapped by NHibernate:
using System;
using System.Collections.Generic;
using System.Reflection;
using NHibernate;
using NHibernate.Persister.Entity;
namespace Stackoverflow.Example
{
/// <summary>
/// NHibernate helper class
/// </summary>
/// <remarks>
/// Assumes you are using NHibernate version 3.1.0.4000 or greater (Not tested on previous versions)
/// </remarks>
public class NHibernateHelper
{
/// <summary>
/// Creates a dictionary of property and database column/field name given an
/// NHibernate mapped entity
/// </summary>
/// <remarks>
/// This method uses reflection to obtain an NHibernate internal private dictionary.
/// This is the easiest method I know that will also work with entitys that have mapped components.
/// </remarks>
/// <param name="sessionFactory">NHibernate SessionFactory</param>
/// <param name="entity">An mapped entity</param>
/// <returns>Entity Property/Database column dictionary</returns>
public static Dictionary<string, string> GetPropertyAndColumnNames(ISessionFactory sessionFactory, object entity)
{
// Get the objects type
Type type = entity.GetType();
// Get the entity's NHibernate metadata
var metaData = sessionFactory.GetClassMetadata(type.ToString());
// Gets the entity's persister
var persister = (AbstractEntityPersister)metaData;
// Creating our own Dictionary<Entity property name, Database column/filed name>()
var d = new Dictionary<string, string>();
// Get the entity's identifier
string entityIdentifier = metaData.IdentifierPropertyName;
// Get the database identifier
// Note: We are only getting the first key column.
// Adjust this code to your needs if you are using composite keys!
string databaseIdentifier = persister.KeyColumnNames[0];
// Adding the identifier as the first entry
d.Add(entityIdentifier, databaseIdentifier);
// Using reflection to get a private field on the AbstractEntityPersister class
var fieldInfo = typeof(AbstractEntityPersister)
.GetField("subclassPropertyColumnNames", BindingFlags.NonPublic | BindingFlags.Instance);
// This internal NHibernate dictionary contains the entity property name as a key and
// database column/field name as the value
var pairs = (Dictionary<string, string[]>)fieldInfo.GetValue(persister);
foreach (var pair in pairs)
{
if (pair.Value.Length > 0)
{
// The database identifier typically appears more than once in the NHibernate dictionary
// so we are just filtering it out since we have already added it to our own dictionary
if (pair.Value[0] == databaseIdentifier)
break;
d.Add(pair.Key, pair.Value[0]);
}
}
return d;
}
}
}
Usage:
// Get your NHiberate SessionFactory wherever that is in your application
var sessionFactory = NHibernateHelper.SessionFactory;
// Get an entity that you know is mapped by NHibernate
var customer = new Customer();
// Get a dictionary of the database column / field names and their corresponding entity property names
var propertyAndColumnNamesDictionary =
Stackoverflow.Example.NHibernateHelper.GetPropertyAndColumnNames(sessionFactory, customer);
Now if I understand correctly here is what you could do....
One way would be to read and parse the XML mapping files from the dll that are embedded before or even after the NHibernate session factory is build. This way you can get all the info you need from the XML files (with column corresponds to which property) and populate a global (probably static) collection of custom objects that will hold the entity's name and a dictionary with key the propery name and value the column name (or the other way around).
You can then access this global collection to get the info you need right after the call to SaveOrUpdate() as you described it.
The downside of this approach is that you need to write your own XML parsing logic to retrive the info you need from the XML mapping files.
An alternative would be to create a custom attribute to decorate each property of your entities in order to get the column name that corresponds to each property.
An example would be:
[ColumnName("MyColumn")]
public string Status { get; set; }
Using reflection you can easily get the property name and the from the attribute the column name that this property is mapped to.
The downside of this approach would be having to keep in sync your column names with the attribute values when the database schema is updated.
Hi all I have a horrid database I gotta work with and linq to sql is the option im taking to retrieve data from. anywho im trying to reuse a function by throwing in a different table name based on a user selection and there is no way to my knowledge to modify the TEntity or Table<> in a DataContext Query.
This is my current code.
public void GetRecordsByTableName(string table_name){
string sql = "Select * from " + table_name;
var records = dataContext.ExecuteQuery</*Suppossed Table Name*/>(sql);
ViewData["recordsByTableName"] = records.ToList();
}
I want to populate my ViewData with Enumerable records.
You can call the ExecuteQuery method on the DataContext instance. You will want to call the overload that takes a Type instance, outlined here:
http://msdn.microsoft.com/en-us/library/bb534292.aspx
Assuming that you have a type that is attributed correctly for the table, passing that Type instance for that type and the SQL will give you what you want.
As casperOne already answered, you can use ExecuteQuery method first overload (the one that asks for a Type parameter). Since i had a similar issue and you asked an example, here is one:
public IEnumerable<YourType> RetrieveData(string tableName, string name)
{
string sql = string.Format("Select * FROM {0} where Name = '{1}'", tableName, name);
var result = YourDataContext.ExecuteQuery(typeof(YourType), sql);
return result;
}
Pay attention to YourType since you will have to define a type that has a constructor (it can't be abstract or interface). I'd suggest you create a custom type that has exactly the same attributes that your SQL Table. If you do that, the ExecuteQuery method will automatically 'inject' the values from your table to your custom type. Like that:
//This is a hypothetical table mapped from LINQ DBML
[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.ClientData")]
public partial class ClientData : INotifyPropertyChanging, INotifyPropertyChanged
{
private int _ID;
private string _NAME;
private string _AGE;
}
//This would be your custom type that emulates your ClientData table
public class ClientDataCustomType
{
private int _ID;
private string _NAME;
private string _AGE;
}
So, on the former example, the ExecuteQuery method would be:
var result = YourDataContext.ExecuteQuery(typeof(ClientDataCustomType), sql);