Using Set/LoadProperty when type for generic isn't known at compile time...

Using Set/LoadProperty when type for generic isn't known at compile time...

Old forum URL: forums.lhotka.net/forums/t/4262.aspx


vdhant posted on Thursday, January 31, 2008

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

simon_may replied on Thursday, January 31, 2008

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

RockfordLhotka replied on Thursday, January 31, 2008

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.

vdhant replied on Thursday, January 31, 2008

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

amselem replied on Thursday, January 31, 2008

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));

 

RockfordLhotka replied on Thursday, January 31, 2008

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));

 



vdhant replied on Thursday, January 31, 2008

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

RockfordLhotka replied on Thursday, January 31, 2008

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



vdhant replied on Thursday, January 31, 2008

Everyone stop sending in issues that way we get beta 2... ;)

ajj3085 replied on Friday, February 01, 2008

Ha.  I am pretty eager for 3.5 too, but at the same time I'm not ready to move to .Net 3.5 so... but think of it this way, if they find all the bugs in beta 1, beta 2 will be bug free and can be moved to the RC and final versions! Wink [;)]

Copyright (c) Marimer LLC