Get properties in native order for DbLinq

A

Andrus

I need to get type t properies in the native order as they appear in class
definition .cs file.
Type t has full-property constructor whose parameters are all properties in
native order.

I tried

public static PropertyInfo[] GetProjectionDataInNativeOrder(Type t) {
PropertyInfo[] props = t.GetProperties();
return props;
}

First call returns properties in proper order.
After some objects of type t are created and their properties accessed
GetProperties() returns props in different order.

How to force this code to return properties in native order always ?

How to change this code so it caches result of first GetProperties() call
for every type and returns previous value returned by GetProperties() ?
Is the property order always native in this case ?

Or any other soution ?

Andrus.
 
J

Jon Skeet [C# MVP]

Andrus said:
I need to get type t properies in the native order as they appear in class
definition .cs file.

You can't. There is absolutely no guarantee that the C# compiler will
leave anything in the IL to indicate the original order.

If you need a particular order, you'll need to specify it in the class.

Or any other soution ?

Yes - make your code less fragile by having another indicator of the
order of the constructors. Using the order in which GetProperties
returns the properties is a recipe for disaster.

The docs for GetProperties make this very clear:

<quote>
The GetProperties method does not return properties in a particular
order, such as alphabetical or declaration order. Your code must not
depend on the order in which properties are returned, because that
order varies.
</quote>
 
A

Andrus

Jon,
If you need a particular order, you'll need to specify it in the class.

I found two ways to solve:

1. Extracted full-property constructor parameter names.
They are same as class properties in my generated code.
..Net must return constructor parameters in native order.
Is this possible and reasonable ?

2. Add column attribute like Ordinal= to every property.

Can anybody point how Linq-SQL solves this issue? I havent found any Ordinal
attribute in ColumnAttribute class in MSDN help.

Yes - make your code less fragile by having another indicator of the
order of the constructors. Using the order in which GetProperties
returns the properties is a recipe for disaster.

The docs for GetProperties make this very clear:

<quote>
The GetProperties method does not return properties in a particular
order, such as alphabetical or declaration order. Your code must not
depend on the order in which properties are returned, because that
order varies.
</quote>

DbLinq calls GetProperties() before every object retrieve. I have
optimization turned off is VCS2008).
I found that in this case first GetProperties() invocation returns
properties in native order.
So I created the following method as quick hack to move forward. Other
methods above seems to require large re-write of code.

Any better idea ?

Andrus.

static Dictionary<Type, PropertyInfo[]> Dict = new Dictionary<Type,
PropertyInfo[]>();

public static PropertyInfo[] GetPropertiesInNativeOrder(Type t) {
PropertyInfo[] props;
if (Dict.ContainsKey(t))
props = Dict[t];
else {
props = t.GetProperties();
Dict.Add(t, props);
}
return props;
}
 
J

Jon Skeet [C# MVP]

Andrus said:
I found two ways to solve:

1. Extracted full-property constructor parameter names.
They are same as class properties in my generated code.
.Net must return constructor parameters in native order.
Is this possible and reasonable ?

Possible. Not great though - it looks like parameter names are
preserved even for release builds, but I don't know if that's
guaranteed.
2. Add column attribute like Ordinal= to every property.

Or attributes to the constructor parameters.
Can anybody point how Linq-SQL solves this issue? I havent found any Ordinal
attribute in ColumnAttribute class in MSDN help.

What makes you think LINQ to SQL has this issue to start with?
DbLinq calls GetProperties() before every object retrieve. I have
optimization turned off is VCS2008).
I found that in this case first GetProperties() invocation returns
properties in native order.
So I created the following method as quick hack to move forward. Other
methods above seems to require large re-write of code.

Avoiding a large rewrite because something happens to work at the
moment despite an explicit warning in the documentation not to rely on
something is a really bad idea.
Any better idea ?

Why do you have this issue in the first place? Are the objects
immutable? If not, can't you just set the properties directly?
 
A

Andrus

Possible. Not great though - it looks like parameter names are
preserved even for release builds, but I don't know if that's
guaranteed.

All .net framework method parameter names are documented.
There are some languages in .net like Python which allow to use named
parameters for methods.

So parameter name saving *is* guaranteed.
What makes you think LINQ to SQL has this issue to start with?

Linq-SQL generated entity class code has probably full parameter
constructors.
To instantiate entity objects, Linq-SQL driver must convert columns returned
from SQL SELECT
command to constructor parameters.
Why do you have this issue in the first place? Are the objects
immutable? If not, can't you just set the properties directly?

I'm trying to fix DbLinq driver code.
Linq driver does not know property names and even entity type names.
All information must be determined at runtime.

I have found also two additional ways:

1. Set every property separately, remove parametherized constructor.
2. Sort constructor parameters in alphabetical order.

Really do'nt know which is the best way to go so trying this dirty hack.

Andrus.
 
J

Jon Skeet [C# MVP]

Andrus said:
All .net framework method parameter names are documented.
There are some languages in .net like Python which allow to use named
parameters for methods.

So parameter name saving *is* guaranteed.

Right. In that case, that's not a *hugely* bad way round it.
Linq-SQL generated entity class code has probably full parameter
constructors.

No, it doesn't. I've just checked.
To instantiate entity objects, Linq-SQL driver must convert columns returned
from SQL SELECT command to constructor parameters.

No, it doesn't. I don't know exactly what it *does* do (it seems to
avoid properties too) but there's no constructor with parameters for it
to call.
I'm trying to fix DbLinq driver code.
Linq driver does not know property names and even entity type names.
All information must be determined at runtime.

None of that stops you from setting properties.
I have found also two additional ways:

1. Set every property separately, remove parametherized constructor.
2. Sort constructor parameters in alphabetical order.

Really do'nt know which is the best way to go so trying this dirty hack.

Setting properties is by far the cleanest way here, IMO.
 
A

Andrus

So parameter name saving *is* guaranteed.
Right. In that case, that's not a *hugely* bad way round it.

I subclass entity base classes to add custom properties by compiling
assembly at runtime.
I need also to add business methods like

public static Customer FindById(string id) {
var q = (from k in Default.Db.Customers
where k.Id == id
select k).SingleOrDefault();
return q;
}

to those dynamic-subclassed entities at design time.

At design time I do'nt know all Customer properties. So I cannot create cs
file containing full-property constructor and thus cannot use subclassing.

Partial assemblies are not supported in .net. Using partial classes requires
compiling business method source code at runtime. This seems not reasonable.

So Adding FindById() to full-parameter constructor class requires creating
separate not-inherited business logic class for every entity. This makes
application unnessecarily complicated.

Is this reasonable ?
No, it doesn't. I don't know exactly what it *does* do (it seems to
avoid properties too) but there's no constructor with parameters for it
to call.

Let's say we have

Db.Customers.ToList()

expression.

Linq-SQL driver must use GetProperties() to find all Customer properties
having ColumnAttribute attributes.
Then it should invoke parameteless constructor to create new Customer entity
and use reflection to set new entity properties, one-by-one.
I see no other way.

However in my case this requires re-writing parts of DbLinq driver code.
Setting properties is by far the cleanest way here, IMO.

I'm in initial stage of development called "probing".
I do'nt have enough resources required to re-write, debug and support
property approach in this stage.

I'm planning to create application quick prototype.
Results of this probe determine will we move to .NET or start looking
something other.

So creating separate business classes for every entity class and using quick
dirty hack to fix
GetProperties() ordering issue seems to be optimal in this case, is'nt it ?

Andrus.
 
J

Jon Skeet [C# MVP]

Andrus said:
I subclass entity base classes to add custom properties by compiling
assembly at runtime.
I need also to add business methods like

public static Customer FindById(string id) {
var q = (from k in Default.Db.Customers
where k.Id == id
select k).SingleOrDefault();
return q;
}

to those dynamic-subclassed entities at design time.

At design time I do'nt know all Customer properties. So I cannot create cs
file containing full-property constructor and thus cannot use subclassing.

To be honest, despite your explanations it's still not at all clear
what you're trying to do. However, it's equally unclear why you're
holding on to this "full-parameter constructor" idea despite it clearly
having issues, when setting properties would appear to be a lot
simpler.
Let's say we have

Db.Customers.ToList()

expression.

Linq-SQL driver must use GetProperties() to find all Customer properties
having ColumnAttribute attributes.
Then it should invoke parameteless constructor to create new Customer entity
and use reflection to set new entity properties, one-by-one.
I see no other way.

I've just had a closer look, and it uses the Storage property of the
Column attribute applied to the relevant property, then sets the field
directly (presumably with reflection).
However in my case this requires re-writing parts of DbLinq driver code.


I'm in initial stage of development called "probing".
I do'nt have enough resources required to re-write, debug and support
property approach in this stage.

I'm planning to create application quick prototype.
Results of this probe determine will we move to .NET or start looking
something other.

So creating separate business classes for every entity class and using quick
dirty hack to fix
GetProperties() ordering issue seems to be optimal in this case, is'nt it ?

Not if the point is to see whether it's suitable for production use -
using a technique which you know shouldn't be used for production seems
like a bad idea to me.

Using the parameter names is more reasonable, however.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top