Hey guys
Just wondering, if i am using the managed fields and I don’t know the type of the object at compile time how do i set/load a field with a value?
The scenario i have is that i want to loop through the fields in a data reader and automatically load the values from the read into the field manager, but to do this at the current time (unless i am missing something) you can only set/load values via generics. So if this is the case i can not loop through these items because I don't know what the type is.
For example CSLA currently wants me to do this something like this:
LoadProperty<Guid>(IdProperty, data.Id);
LoadProperty<string>(NameProperty, data.Name);
But i need to be able to go (note this isn't complete but it shows what i am trying to do):
for (int i = 0; i < dataReader.FieldCount; i++)
LoadProperty(dataReader.GetName(i), dataReader.GetValue(i));
Any ideas let me know. Also if a new with the above loop scenario i can also get out the type of the current columns object, but this doesn't really help with the current requirement for generics if a simple solution if desired.
Thanks
Anthony
I have not caught up with the new property management stuff in CSLA 3.5 yet, however FWIW, may initial take is that you are going to have to use reflection to resolve the correct generic method. MakeGenericMethod will come into play to close the genericity of the MethodInfo after you have reflected out the open generic MethodInfo.
Hope that points you in the right direction as I havent had to go there yet
That's an interesting scenario, and not one I'd thought of. Though I do have some half-baked DataMapper code I'm still working on that has a similar issue - but I'd planned to solve that with some internal methods. Maybe those methods should be protected internal.
Specifically, LoadProperty() and ReadProperty() methods that are non-generic and do coercion of the value. The PropertyInfo object knows the required end-type and so it is quite possible for these methods to coerce the supplied value into the needed type (unless it can't be coerced, in which case there'd be an exception).
But it still won't work quite like your code, because the managed field API only accepts PropertyInfo objects to identify a property - never just the property name. The PropertyInfo is required because it supplies other important information beyond just the name (such as the required type of the field).
As you probably know, I made a lot of changes to this post-Beta 1 due to fast feedback on the forum. There'll be a method on FieldDataManager you can use inside your business object to get a list of the PropertyInfo objects for your object - kind of like a high-speed replacement for using reflection.
Definitely if you have a LoadProperty() and ReadProperty() that provide a non-generic signature would be a big plus. Simply from the point of view of creating core methods that can load and set properties automatically and various other situations that i can think of.
Keep us informed on anything that you have planned in area. It would be greatly appreciated.
Thanks
Anthony
I don't have looked too much into the CSLA 3.5 code so maybe this is a nonsense, but can't you simply use generics with the Object type?
LoadProperty<Object>(datareader.GetName(i), dataReader.GetValue(i));
Yeah, maybe. That was my original thought. But the method
requires a PropertyInfo<T>, and you wouldn’t have a
PropertyInfo<object> - normally at least.
But the new methods I added today should help. For example:
LoadProperty(propertyInfo, dataReader.GetValue(i));
The first parameter is the polymorphic IPropertyInfo type, so
any PropertyInfo<T> will work, regardless of T. You could create your own
subclass of PropertyInfo<T> that extends the type to include the ordinal
position of the value in the datareader, or the column name. Then your code
would be like:
var propertyList = FieldManager.GetRegisteredProperties();
foreach (var p in propertyList)
LoadProperty(p, dataReader.GetValue(((IExtendedPropertyInfo)p).DataIndex));
Or
var propertyList = FieldManager.GetRegisteredProperties();
foreach (var p in propertyList)
LoadProperty(p, dataReader.GetValue(((IExtendedPropertyInfo)p).ColumnName));
Again, you’d need to have created a custom interface
(IExtendedPropertyInfo) and a custom subclass (ExtendedPropertyInfo<T>)
that added either that DataIndex or ColumnName property. Then your property registration
would be:
private static ExtendedPropertyInfo<string> NameProperty =
RegisterProperty<string>(typeof(myobject), new ExtendedPropertyInfo<string>(“Name”,
“S_NAME”));
Notice the column name being provided to the constructor.
A positive side-effect: this overload uses the same type
coercion used by DataMapper, which is seriously nice stuff! For example,
suppose your property type is an enum and the database value is a string. This
line of code will automatically parse the string into the enum type. And it
will do all sorts of date conversions to handle DateTime, DateTime?,
DateTimeOffset, SmartDate, etc. And lots of other stuff like that.
Rocky
From: amselem
[mailto:cslanet@lhotka.net]
Sent: Thursday, January 31, 2008 5:57 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Using Set/LoadProperty when type for generic
isn't known at compile time...
I don't have looked too much into the CSLA 3.5 code so maybe this is a
nonsense, but can't you simply define use generics with the Object type?
LoadProperty<Object>(datareader.GetName(i), dataReader.GetValue(i));
Sounds like a great solution. Do you think that there will be much of a performance difference between the generic versions and this new version?
"A positive side-effect: this overload uses the same type coercion used by DataMapper, which is seriously nice stuff! For example, suppose your property type is an enum and the database value is a string. This line of code will automatically parse the string into the enum type. And it will do all sorts of date conversions to handle DateTime, DateTime?, DateTimeOffset, SmartDate, etc. And lots of other stuff like that."
And yes this does sound really cool. Just one question through, i am assuming that the overload you are referring to is "LoadProperty(p, dataReader.GetValue(((IExtendedPropertyInfo)p).DataIndex));". Meaning that when i load the property the mapping/date conversions will happen automatically?
Also when is Beta 2 coming out? How long have you got planned before we get another release?
Thanks for the great work.
Anthony
There are different possibilities performance-wise.
The generic versions avoid casting/boxing/unboxing in most
cases, because the type is known and flows through. There’s a little
casting to get the IFieldData to be IFieldData<T>, but the actual value
does need a cast or box/unbox. The non-generic version obviously would
box/unbox any primitive value because the intermediate type is object.
The coercion is reasonably smart. If the source and target types
are the same then it does no work. It only does coercion if the source and
target types are different. I suppose, though, that they’ll always be
different when coming from a datareader – but that’d be true with
the generic overloads too – those SqlClient data types must always be coerced
into native .NET types I suppose.
So in the end, I’m guessing (for the datareader scenario)
there should be little to no perf difference.
I don’t know when beta 2 will come out. People are
identifying issues with beta 1 and it is just a couple days old. It is _wonderful_
how much testing is being done – thank you all!! Beta 2 will come
out when the bug reports for beta 1 dry up J
Rocky
From: vdhant
[mailto:cslanet@lhotka.net]
Sent: Thursday, January 31, 2008 8:17 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: Using Set/LoadProperty when type for
generic isn't known at compile time...
Sounds like a great solution. Do you think that there will be much of a
performance difference between the generic versions and this new version?
"A positive side-effect: this overload uses the same type coercion used
by DataMapper, which is seriously nice stuff! For example, suppose your
property type is an enum and the database value is a string. This line of code
will automatically parse the string into the enum type. And it will do all
sorts of date conversions to handle DateTime, DateTime?, DateTimeOffset,
SmartDate, etc. And lots of other stuff like that."
And yes this does sound really cool. Just one question through, i am assuming
that the overload you are referring to is "LoadProperty(p,
dataReader.GetValue(((IExtendedPropertyInfo)p).DataIndex));". Meaning that
when i load the property the mapping/date conversions will happen
automatically?
Also when is Beta 2 coming out? How long have you got planned before we get
another release?
Thanks for the great work.
Anthony
Copyright (c) Marimer LLC