Andrus said:
I hope that this causes assembly containing Customer class to be
loaded only when customer table is referenced. Wihtout this database
content initialization code creates customer class and this causes
customer and all other extended entity assemblies to be loaded at
application startup always.
Ok, but take a step back for a minute: these assemblies, they're
created on-site at the client, I pressume? Otherwise you wouldn't be
needing them.
So your code accessing these custom types has to be generic, i.o.w.:
it's very very hard to make that reliable.
Customer is based on CustomerBase class. CustomerBase class has known
fields at design time.
So autocomplete, stong typing, refactoring etc. are available at
design time.
Code is very well maintainable.
No, see below.
Since Customer is based on CustomerBase, runtime can add only
user-defined new properties, not changing base class.
This allows to make customer-specific customizations easily, e.q bind
customer lists to datagridview.
Sure, but you can't access these user defined properties in your code,
at least not in a typed fashion. So IF you want to work with these,
you've to fall back on low-level property descriptor voodoo, which is
IMHO not preferable and definitely not maintainable.
Also, your complete application isn't really testable, because the
stuff added for the client is unknown.
I can create C# scripts running in customer sites which use those
extended customer properties.
In this case I can use all static language goodies together with
basic, well tested core application.
How can you write code off-site which accesses in a typed fashion
properties which are added later on?
So I do'nt understand why I cannot use extended properties in customer
sites.
Also using extended properties in business objects is only reasonable
way to add customer specific calculated fields to grids.
No, there are other ways. The thing is that the properties in the
grids are just a facade. You have to implement ITypedList and from then
on you can return whatever you want in property descriptors to make up
a flat list, which for example isn't a flat list at all.
What you want is to add for example 'DutchAddress' to a Customer class
at the client's site, however you can't access DutchAddress in your own
code, as that's compiled and written and tested without that property
on the Customer class. Sure, at runtime you can have binding perhaps,
but that's about it. Where's your validation logic and above all, where
do you test your validation logic for 'DutchAddress' ?
The typical pattern to implement flexible fields in entities is by
using meta-tables, although it's a sucky approach as well, but it's
better than messing with code you can't test on the client's site.
Meta tables work with a couple of tables, where you define 1:n
relations between the extended entity and the list of properties to add
as well. This can be implemented in your code without a problem and
tested. You can even create a UI to create these fields.
As the properties are really 1:n related objects to your 'customer'
entity, you then create an ITypedList implementation on your list to
bind to a grid. That ITypedList implementation returns the Customer
property descriptors but also creates property descriptors for the 1:n
related extra property objects.
Do a search on google about implementing ITypedList, or search my blog
for the article I wrote about this.
Extended properies design pattern allows to use strong typing in core
appliction with core
properties and customer specific plugins/scripts running at customer
sites. This allows to use same application with exteneded data and
thus provides huge development cost saving.
Moving to untyped datasets loses all strong typing benefits, I must
cast values from strings and use ugly indexing syntax. Datasets are
less scalable and are not developed by MS anymore.
So I have no idea why you recommend to use untyped datasets.
Ah, so you're saying that at your location you can write code which
can deal with property FooBar on 'Customer' while there's no Foobar
property at the moment, which is added later on at the client's site?
WHere is the validation logic for FooBar written, as it's not there
yet? Also at the client's site? And where do you test Foobar and its
validation? Also at the clients site? Or not at all?
Yes, in Python it is possible write exception handler inside entity
class which catches missing property exception and returns propery
value corresponding to database column.
I was surprised that this basics capability is not available in .NET.
IIRC python is a dyn. language and not statically typed. Similar to
Ruby, which is ideal for the project you're working on. C# is a
statically typed language, if you want to add properties to a type at
runtime, you can't, it has to be via subclassing. The thing is that if
you do that, you have to take into account this subclass and its
properties. It's not a real problem per se, UNLESS you need to work
with these extra properties in your ORIGINAL code, because that
original code isn't aware of these extra properties nor the subclass.
(via 'dynamic proxy', you can extend classes at runtime in C#, however
code which isn't aware of the added stuff can't work with that extra
stuff, as it doesn't know it's there at compile time. The code which IS
aware of the extra stuff can of course, but imho in your project that's
not code which does exist.
Ideablade DevForce supports it well.
There is special lesson teaching this freely downloadable from
IdeBlade website.
It's a trick, but it has consequences: the thing isn't adding the
property, dynamic proxy can do that, the thing is the code working with
the added property. If I write a validator for Customer, I can't add to
the validator some code working with properties which are added at
runtime by a subclass, because the compiler doesn't know about these
properties.
THAT's what I meant.
With dynamic proxy (the pattern you follow as well, though you
generate the proxy with a script), there's no end to what you can add
to a class. That's not the point. The point is: can you write provable
code which is correct when you say to your client: "It's done"?
You can only do that if you have in your OWN code tests and compile
time checked code which uses the code added at runtime. You can't do
that in C#, as you can't write code which compiles now against
properties which aren't there yet. You can't write validator,
authorizer and what not code which works with properties added at
runtime as they're not there yet.
Adding properties at runtime using dyn. proxy is maybe half a day of
work, but that's just a small part of the puzzle.
I expect that in future every reasonable ORM supports this. ORMs
without dynamic property support will vanish.
Haha no way.
Keywords: provable code.
The one thing which counts is that you can proof your code is correct,
that what you give to your client is working code, that the validation
etc. code works properly. As you can't write validation code up front
against stuff that's not there yet, your code can only be provably
correct if the validation code is written AFTERWARDS, but that's not a
dynamic system.
In the past 5 years we have had a couple of customers who also wanted
to extend the entity classes with properties at runtime. We can do that
for fetching (see:
http://weblogs.asp.net/fbouma/archive/2006/06/09/LLBLGen-Pro-v2.0-with-A
SP.NET-2.0.aspx where I add scalar aggregate fields at runtime to
entities)
but for saving it's not that possible, because where do you put the
validation logic you have to test ? Or better: how do you test code
which has to work with stuff that's not there?
FB
--
------------------------------------------------------------------------
Lead developer of LLBLGen Pro, the productive O/R mapper for .NET
LLBLGen Pro website:
http://www.llblgen.com
My .NET blog:
http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------