How access to Storage-Property in c#? - c#

I mapped some access-tables to classes. I created properties and bound them to columns. I used the Storage-property like the following
string _ColValue;
[Column(Storage = "_ColValue")]
public string ColValue
{
get { return _ColValue; }
set { _ColValue = value; }
}
The columns contains string values but they have many spaces at the end. They come always with a constant length. Now I want to trim the values to remove the spaces. I thougt it would be nice to manipulate the string directly while mapping from the datatable to my properties.
My intesion was to iterate all private fields of mapped properties in a method i call in the constructor.
void TrimPropValues()
{
FieldInfo[] fi = this.GetType().GetFields(BindingFlags.NonPublic
| BindingFlags.Instance);
foreach (FieldInfo fiItem in fi)
{
if (fiItem.FieldType.Equals(typeof(string))
&& fiItem.GetValue(this) != null)
{
fiItem.SetValue(this, fiItem.GetValue(this).ToString().TrimEnd(' '));
}
}
}
When I call the method in the constructor, the fields are not filled. The mapping seems happen later. What is the right moment to call the method? When does the mapping happen or rather how can I reach the moment of mapping?

You can encapsulate this nicely in the context subclass itself:
public class MyContext : DbContext
{
public MyContext()
: base()
{
((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized += (sender, e) =>
{
TrimStringValues(Entry(e.Entity));
};
}
void TrimStringValues(DbEntityEntry entry)
{
foreach (var property in entry.CurrentValues.PropertyNames)
{
var currentValue = entry.CurrentValues[property] as string;
if (currentValue != null)
entry.CurrentValues[property] = currentValue.Trim();
}
}
}
In the context's constructor the underlying ObjectContext's ObjectMaterialized event is subscribed to. In the event handler, each materialized entity is subjected to the TrimStringValues method. In this method, EF's own infrastructure is used to trim string values. This is faster than doing the same by reflection.

Related

Why I can't assign dynamic data in constructor C#?

I'm a PHP Developer...
I need to do a class that can be created and fill of dynamic way, similar to this in PHP.
class Person{
private $name;
private $age;
function __construct($params = array()){
foreach ($this as $key => $val) {
$this -> $key = (isset($params[$key])) ? $params[$key] : "";
}
}
function getName(){
return $this->name;
}
function getAge(){
return $this->age;
}
function setName($value){
$this->name = $value;
}
function setAge($value){
$this->age = $value;
}
}
I read about the reflection in C#, but I don't find the correct way to do.
This is my C# code
public class Person
{
private String _name { get { return _name; } set { _name = value; } }
private int _age { get { return _age; } set { _age = value; } }
public Person()
{
}
public Person(Hashtable _data)
{
PropertyInfo[] propertyInfos;
propertyInfos = typeof(Person).GetProperties(BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var propInfo in propertyInfos)
{
typeof(Person).GetProperty(propInfo.Name).SetValue(this, _data[propInfo.Name]);
}
}
}
In runtime I get an Exception
Object reference not set to an instance of an object.
The typeof(Person) I try to change it to this.getType() and I get the same.
I hope that can help me.
You are grabbing all properties on the object and then looking them up in the hashtable. You likely want the reverse--all objects in the hashtable set to properties on the object. Otherwise you'll get an exception when you don't specify every single member.
As Alexei points out, the NullReferenceException is due to the second call to GetProperties only returning public properties when no BindingFlags are supplied. Since there are no public properties, you get an exception.
Because C# is strongly typed, you run into a number of issues you don't have in PHP. These include setting a value with an object of a type that doesn't match or convert to the property type, entries in your data parameter that don't exist as properties, etc. I've done my best to document the gotchas I see below.
Here is what the Person class would look like (I've cleaned up some of the style and used classes to make it feel more like a C# class):
public class Person
{
private string name { get; set; }
private int age { get; set; }
public Person()
{
}
public Person(IDictionary<string,object> data)
{
foreach (var value in data)
{
// The following line will be case sensitive. Do you need to standardize the case of the input dictionary before getting the property?
PropertyInfo property = typeof(Person).GetProperty(value.Key, BindingFlags.Instance | BindingFlags.NonPublic);
if (property != null)
{
property.SetValue(this, value.Value); // You are allowing any old object to be set here, so be prepared for conversion and casting exceptions
}
else
{
// How do you want to handle entries that don't map to properties? Ignore?
}
}
}
}
And here is an example of usage:
static void Main(string[] args)
{
var person = new Person(new Dictionary<string,object>() {{"name" ,"Mike"}, {"age", 32}});
}
You should stay away from using var if you're new to the language, it only complicates things.
The propInfo in your foreach-loop already is a PropertyInfo, so you don't need to find it again:
BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance;
PropertyInfo[] propertyInfos = typeof(Person).GetProperties(flags);
foreach (PropertyInfo propInfo in propertyInfos)
{
propInfo.SetValue(this, _data[propInfo.Name]);
}
The NullReferenceException is probably caused by the following part of your original code:
typeof(Person).GetProperty(propInfo.Name)...
Since no BindingFlags are provided to the GetProperty() this time, it looks for public instance properties, and when no such property is found, it returns null (that, or _data is null to begin with).
As others have pointed out, your properties currently will cause StackOverflowExceptions. Try changing them to:
private String _name { get; set; }
private int _age { get; set; }
I am wondering why you would want to do this. There may be better, more idiomatic C#, designs to achieve the behavior you want. But we can't know that because there is no additional contextual information mentioned in the question.
So I will simply try to answer your question. The version below takes your code, using auto properties, and a simple dictionary lookup for the initialization of its members from the supplied dictionary. Also note that this does not require any reflection, because there is nothing dynamic about the members of this class.
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Person(IDictionary<string, object> data)
{
// What to do if the map does not contain "Name" or "Age" ?
// Right now: initialize to default value.
Name = TryLookup<string>(data, "Name", null);
Age = TryLookup<int>(data, "Age", default(int));
// What to do if the map contains other items that do not
// map to a member variable?
}
private static T TryLookup<T>(IDictionary<string, object> data, string key, T defaultValue)
{
return data.ContainsKey(key) ? (T)data[key] : defaultValue;
}
}
In case you actually really really badly need a dynamic type as opposed to a statically defined type with fixed member properties, you could use an ExpandoObject or alternatively (but this is far from trivial) build a dynamic type using an AssemblyBuilder with a TypeBuilder

Importing XML to Objects Recursively

I am trying to write a method which uses reflection in order to get the properties and set their values while traversing XElement:
Lets say I have a class like this which only provides me XML value to be parsed:
class XMLController
{
public string XML
{
get{
return #"<FieldGroup name='People' count='20'>
<Fields>
<Field Name='Jon' LastName='McFly'/>
<Field Name='Michael' LastName='Jackson'/>
</Fields>
</FieldGroup>";
}
}
}
And this is how my Objects look like:
class FieldGroup
{
public string Name {get;set;}
public string Count {get;set;}
public IEnumerable<Field> Fields {get;set;}
}
class Field
{
public string Name {get;set;}
public string LastName {get;set;}
}
The mapper method traverses XElement and since the Node names are matching names with the Objects I am thinking this helps little more but I haven't come up with something really useful. I don't want to pass the type but rather, the method will work with almost every XML passed in with the same format.
All it knows the fact that the XML nodes and attributes are matching names.
This is what I've done but didn't really worked:
class XMLObjectMapper
{
public T Map<T>(XElement element) where T: class, new()
{
T entity = (T) Activator.CreateInstance(typeof(T));
if(element.HasAttributes)
{
MapXMLAttributesToObject<T>(element,entity);
}
if(element.HasElements)
{
foreach (var childElement in element.Elements())
{
//if the child element has child elements as well, we know this is a collection.
if(childElement.HasElements)
{
var property = GetProperty<T>(childElement.Name.LocalName);
property.SetValue(entity,new List<property.PropertyType>());
Map<T>(childElement);
}
else
{
var property = GetProperty<T>(childElement.Name.LocalName);
var type = Activator.CreateInstance(property.PropertyType);
type.Dump();
}
}
}
return entity;
}
private void MapXMLAttributesToObject<T>(XElement element, T entity)
{
foreach(XAttribute attribute in element.Attributes())
{
var property = GetProperty<T>(attribute.Name.LocalName);
property.SetValue(entity,attribute.Value);
}
}
private PropertyInfo GetProperty<T>(string propertyName)
{
return typeof(T).GetProperty(propertyName,BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
}
}
You're on the right track, but as you've noticed, you've got some errors.
The following piece of code doesn't compile because you can't use a value (property.PropertyType) in place of a type name. C# is a statically typed language, so types have to be known at compile time rather than being in variables:
new List<property.PropertyType>()
However, if you use reflection, you can choose the types at runtime. We can do this instead:
Activator.CreateInstance(typeof(List<>).MakeGenericType(collectionElementType))
The other problem that you have is that you can't just call Map<T>(childElement). First of all, T is not the right type -- it's the parent element's type, not the child's. Secondly, the child is actually a collection, and Map<T> doesn't know how to handle collections, only individual objects. We have to loop over the child elements, map onto each single one (calling Map<T> with the type of the elements in the collection -- in your example, Map<Field), and then add them all to the collection. I've made a new version of your Map<T> that works:
public T Map<T>(XElement element) where T : class, new()
{
T entity = (T)Activator.CreateInstance(typeof(T));
if (element.HasAttributes)
{
MapXMLAttributesToObject<T>(element, entity);
}
if (element.HasElements)
{
foreach (var childElement in element.Elements())
{
var property = GetProperty<T>(childElement.Name.LocalName);
// If the child element has child elements as well, we know this is a collection.
if (childElement.HasElements)
{
// Assume collections are of type IEnumerable<T> or List<T>
var collectionElementType = property.PropertyType.GetGenericArguments()[0];
// var collectionValue = new List<collectionElementType>()
var collectionValue = Activator.CreateInstance(typeof(List<>).MakeGenericType(collectionElementType));
foreach (var grandchildElement in childElement.Elements())
{
// var collectionElement = this.Map<collectionElementType>(grandchildElement);
var collectionElement = this.GetType().GetMethod("Map").MakeGenericMethod(collectionElementType).Invoke(this, new object[] { grandchildElement });
collectionValue.GetType().GetMethod("Add").Invoke(collectionValue, new object[] { collectionElement });
}
property.SetValue(entity, collectionValue, null);
}
else
{
// I'm not sure what this should do -- this case doesn't happen in your example.
throw new NotImplementedException();
}
}
}
return entity;
}
It certainly needs some more error handling, and I'm assuming you wanted to do something useful in the case where I threw a NotImplementedException. However, it works on your sample.

LINQ Changes Not Recognized When Using Generics

I am currently trying to create a Class which employs generics in order to reduce the amount of work needed for future development. As I add Tables to the LINQ To SQL Designer, certain basic Methods are used in each one. Rather than reproduce them in every Partial Class associated with every new Table, I would like to employ a single generic Class. The issue is that any changes made to the Entities are not recognized and therefore not submitted.
Public Partial Class ABC
{
Public Static Bool Synchronize(string source, string destination)
{
try
{
DataContext destinationDB = DataConnection.Destination(destination);
Table<ABC> destinationABCs = destinationDB.ABCs;
DataContext sourceDB = DataConnection.Destination(source)
Table<ABC> sourceABCs = sourceDB.ABCs;
foreach (ABC ABCCode in sourceABCs)
{
ABC destABCCode = destinationABCs.SingleOrDefault(x => x.Id == ABCCode.Id);
bool same = EntityProcessing.AreIdentical(ABCCode, destABCCode);
if (same == false)
{
destABCCode = (ABC)EntityProcessing.Synchronize(ABCCode, destABCCode);
}
}
ChangeSet test = destinationDB.GetChangeSet(); // Test Line For Debugging
destinationDB.SubmitChanges();
}
return true;
}
}
The next Class is:
Public Static Class EntityProcessing
{
Public Static Bool AreIdentical(Object sourceEntity, Object destinationEntity)
{
if (sourceEntity.GetType() == destinationEntity.GetType())
{
Type t = sourceEntity.GetType();
FieldInfo[] tList = t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
foreach (FieldInfo fi in tList)
{
if ((fi.GetValue(sourceEntity) != null ? fi.GetValue(sourceEntity).ToString()
: null) == (fi.GetValue(destinationEntity) != null ?
fi.GetValue(destinationEntity).ToString() : null))
{ continue; }
else
{ return false; }
}
return true;
}
else
{ return false; }
}
Public Static Object Synchronize(Object sourceEntity, Object destinationEntity)
{
if (sourceEntity.GetType() == destinationEntity.GetType())
{
Type t = sourceEntity.GetType();
FieldInfo[] tList = t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
foreach (FieldInfo fi in tList)
{
fi.SetValue(destinationEntity, fi.GetValue(sourceEntity));
}
}
return destinationEntity;
}
}
I have tried modifying the EntityProcessing.Synchronize method into a Void method as well. Neither works. Both will return the correct Entity with the Fields set to the appropriate results. The issue lies in the fact that LINQ does not recognize the Entities as having changed.
If I add a temporary line of ChangeSet test = destinationDB.GetChangeSet();, the Updated count is zero. The loss appears to be in the conversion to Objects.
I have tried setting the Parameter Type to ABC on the EntityProcessing.Synchronize() method and modifying a Field, and the Updated count in test is correct. How do I resolve this?
How do I submit the updated entities to the database or rather, how do I get LINQ to recognize these entities are being changed and needing an update?
Do you mean: Public Static Bool Synchronize<ABC>(string source, string destination) with "ABC" as the generic type?
However, I don't think your .ABCs will work that simply. You may have to use reflection to get at the proeprty with that particular name. For example, first use reflection to get the name of the type parameter (ABC), and then use reflection to get the table field from the data source based on this type name.

ASP.Net MVC 2 Controller's TryValidate doesn't validate the List<> items within the model

How do you get a model's validation to also validate child objects in a generic list property.
I have a model that I'm trying to validate, this is not what's being posted to the server, but a composite of some information posted, and information already on the server... for example.
...
public class A {
[Required]
public string Property1 { get; set; }
}
...
public class B {
public List<A> Values { get; set; }
}
...
if (!TryValidateModel(instanceofB))
{
//this should fire, as one of A inside B isn't valid.
return View(instanceofB);
}
When I try to validate the model instance of B, it won't validate the Values collection for their validation attributes.
The TryValidateModel method only goes down one level so it only checks for Validation attributes on the object of type B, not on its nested objects. One way to overcome this is to define your own implementation of a ValidationAttribute:
public class ListValidationAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
IEnumerable enumerable = value as IEnumerable;
// If the input object is not enumerable it's considered valid.
if (enumerable == null)
{
return true;
}
foreach (object item in enumerable)
{
// Get all properties on the current item with at least one
// ValidationAttribute defined.
IEnumerable<PropertyInfo> properties = item.GetType().
GetProperties().Where(p => p.GetCustomAttributes(
typeof(ValidationAttribute), true).Count() > 0);
foreach (PropertyInfo property in properties)
{
// Validate each property.
IEnumerable<ValidationAttribute> validationAttributes =
property.GetCustomAttributes(typeof(ValidationAttribute),
true).Cast<ValidationAttribute>();
foreach (ValidationAttribute validationAttribute in
validationAttributes)
{
object propertyValue = property.GetValue(item, null);
if (!validationAttribute.IsValid(propertyValue))
{
// Return false if one value is found to be invalid.
return false;
}
}
}
}
// If everything is valid, return true.
return true;
}
}
Now List<A> can be validated using the attribute:
public class B
{
[ListValidation]
public List<A> Values { get; set; }
}
I haven't tested performance for the above approach thoroughly but if in your case that turns out to be a problem, an alternative approach is to use a helper function:
if (!ValidateB(instanceofB))
{
//this should fire, as one of A inside B isn't valid.
return View(instanceofB);
}
...
public bool ValidateB(B b)
{
foreach (A item in b.Values)
{
if (!TryValidateModel(item))
{
return false;
}
}
return true;
}
I had a similar issue that I fixed by avoiding the call to TryValidate altogether. The reason I called TryValidate was because I needed to do make some changes on my model and then do the validation. I ended up creating an interface for the model and replaced the default model binder with one that recognizes the interface and calls my method. This all happens before the framework calls validate the first time (which is recursive).

Convert Nulls to Empty String in an object

What is the easiest way to take an objects and convert any of its values from null to string.empty ?
I was thinking about a routine that I can pass in any object, but I am not sure how to loop through all the values.
When your object exposes it's values via properties you can write something like:
string Value { get { return m_Value ?? string.Empty; } }
Another solution is to use reflection. This code will check properties of type string:
var myObject = new MyObject();
foreach( var propertyInfo in myObject.GetType().GetProperties() )
{
if(propertyInfo.PropertyType == typeof(string))
{
if( propertyInfo.GetValue( myObject, null ) == null )
{
propertyInfo.SetValue( myObject, string.Empty, null );
}
}
}
Using reflection, you could something similar to :
public static class Extensions
{
public static void Awesome<T>(this T myObject) where T : class
{
PropertyInfo[] properties = typeof(T).GetProperties();
foreach(var info in properties)
{
// if a string and null, set to String.Empty
if(info.PropertyType == typeof(string) &&
info.GetValue(myObject, null) == null)
{
info.SetValue(myObject, String.Empty, null);
}
}
}
}
Presumably, you have a report or a form somewhere showing "null" all over the place, instead of a nice, pleasant "".
It's best to leave the nulls as they are, and modify your display code wherever appropriate. Thus, a line like this:
label1.Text = someObject.ToString();
should become:
if (someObject == null)
{
label1.Text = ""; // or String.Empty, if you're one of *those* people
}
else
{
label1.Text = someObject.ToString();
}
and you can functionalize it as necessary:
public void DisplayObject(Label label, Object someObject)
{
if (someObject == null)
{
label.Text = ""; // or String.Empty, if you're one of *those* people
}
else
{
label.Text = someObject.ToString();
}
}
You could use reflection. Here's an example with one level of nesting:
class Foo
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public string Prop3 { get; set; }
}
class Program
{
static void Main(string[] args)
{
var foo = new Foo
{
Prop1 = (string)null,
Prop2 = (string)null,
Prop3 = (string)null,
};
var props = typeof(Foo).GetProperties()
.Where(x => x.PropertyType == typeof(string));
foreach (var p in props)
{
p.SetValue(foo, string.Empty, null);
}
}
}
You can do that via reflection without too much trouble, and I am sure that by the time I post this there will be answers that tell you exactly how to do that.
But I personally don't like the reflection option.
I prefer to maintain object invariants for all of the object's members through a variety of means. For string members, the invariant is often that it not be null, and sometimes there are maximum length requirements as well (for storage in a database, for example). Other members have other sorts of invariants.
The first step is to create a method that checks all the invariants that you define for the object.
[Conditional("DEBUG")]
private void CheckObjectInvariant()
{
Debug.Assert(name != null);
Debug.Assert(name.Length <= nameMaxLength);
...
}
Then you call this after any method that manipulates the object in any way. Since it is decorated with the ConditionalAttribute, none of these calls will appear in the release version of the application.
Then you just have to make sure that none of the code allows any violations of these invariants. This means that the string fields need to have either initializers in their declarations or they need to be set in all the constructors for the object.
A special problem, and the one that probably motivated this question, is what to do about automatic properties.
public string Name { get; set; }
Obviously, this can be set to null at any time, and there's nothing you can do about that.
There are two options with regard to automatic properties. First, you can just not use them at all. This avoids the problem entirely. Second, you can just allow any possible string value. That is, any code that uses that property has to expect nulls, 10 mb strings or anything in between.
Even if you go with the reflection option to remove nulls, you still have to know when to call the magic-null-removal method on the object to avoid NullReferenceExceptions, so you haven't really bought anything that way.
+1 to Tanascius's answer. I used this answer but tweaked it a bit.
First I only grab the properties that are strings, so it doesn't loop through all my properties. Secondly, I placed in it my BaseEntity class that all my entities inherit from, which makes it global, so I don't have to put it on all my Entities.
public class BaseEntity
{
public int Id { get; set; }
public BaseEntity()
{
var stringProperties = this.GetType().GetProperties().Where(x => x.PropertyType == typeof(string));
foreach (var property in stringProperties)
{
if (property.GetValue(this, null) == null)
{
property.SetValue(this, string.Empty, null);
}
}
}
}

Categories

Resources