Empty String -> Null

Posts   
1  /  2
 
    
Posts: 65
Joined: 07-Dec-2005
# Posted on: 26-Dec-2005 21:28:13   

Let me preface this by stating that I understand the philosophical difference between an empty string and null (in the database world). However, with what we're dealing with, they're essentially the same. Is there a way to specify, aside from changing my usage code, that an empty string assignment to a string column should be saved as a null in the database?

Walaa avatar
Walaa
Support Team
Posts: 14986
Joined: 21-Aug-2005
# Posted on: 26-Dec-2005 22:21:12   

Is there a way to specify, aside from changing my usage code...

Do you mean on the database side?if so it may depend on which database server you use, for example Oracle says the following: Oracle currently treats a character value with a length of zero as null. However, this may not continue to be true in future releases, and Oracle recommends that you do not treat empty strings the same as nulls.

If you don't mean on the database side then I don't know if you were generally speaking or were refering to using the code generated by LLBLGen Pro, if the later was the case then you may use the OnBeforeEntitySave event and assign the string a value of null just before the entity is saved.

Posts: 65
Joined: 07-Dec-2005
# Posted on: 26-Dec-2005 23:19:25   

Actually, I'm creating an abstract class that inherits from EntityBase, then changing the template for my entities to inherit from my class instead of EntityBase.

In my class, I override SetNewFieldValue, then if the value is a string, it is empty when trimmed, and the column is nullable, I assign null to the value.

Paul.Lewis
User
Posts: 147
Joined: 22-Aug-2005
# Posted on: 27-Dec-2005 04:16:38   

AdamRobinson wrote:

Actually, I'm creating an abstract class that inherits from EntityBase, then changing the template for my entities to inherit from my class instead of EntityBase.

In my class, I override SetNewFieldValue, then if the value is a string, it is empty when trimmed, and the column is nullable, I assign null to the value.

Adam,

This may or may not be helpfull, but I'll offer it as a thought:

_NULL values are not usable inside .NET since, for example, a field of type int/Integer, which can be NULL in the database, can't be null/Nothing in .NET. LLBLGen Pro's generated code converts all NULL values for all fields to default values for each type. These values are defined in the Helper class 'TypeDefaultValue'. Each DAO object automatically receives an instance of this class so it can convert NULL values from the database automatically. You can change these default values in the TypeDefaultValue class to other values, however keep in mind that these default values are not used most of the time : you always have to test for NULL for a given field, if it was NULL when the data was fetched from the database. To test a given field if it was NULL when you read it from the database, use TestOriginalFieldValueForNull(): ****_

This paragraph was lifted from the "Generated code - Using the entity classes, SelfServicing" page of the LLBLGen programmers guide. Perhaps you could simply overrife the TypeDefaultValue helper class for strings?

Walaa avatar
Walaa
Support Team
Posts: 14986
Joined: 21-Aug-2005
# Posted on: 27-Dec-2005 06:06:32   

Adam,

What's wrong with the your approach? isn't it working?

Posts: 65
Joined: 07-Dec-2005
# Posted on: 27-Dec-2005 15:43:35   

Paul,

Thanks for the response. However, that passage applies only to value types (int, datetime, etc.), not to reference types (strings, entities, etc.). Reference types can be null. My original post was regarding the actual storage of the value in the fields object, using null instead of a string that, when trimmed, would be empty (either "" or a string consisting only of spaces).

Waala,

I'm working with it now, however, as the actual method that gets called by the entity classes to set the value is not virtual (another of its overloads is, but that particular one is not), I've been forced to using a "new" instead of override on the function. Though this works for practical purposes, it will not properly polymorph (ie if I reference the entity as an EntityBase instead of my class or the actual entity, it will not trickle down to my function properly).

Franz, any chance on having that method be virtual in the next release? It's the one that has four parameters, the last two being booleans.

Walaa avatar
Walaa
Support Team
Posts: 14986
Joined: 21-Aug-2005
# Posted on: 27-Dec-2005 16:00:04   

The exposed virtual function SetNewFieldValue(int fieldIndex, object value, bool checkForRefetch) internally calls the other function passing true as the last parameter, as follows SetNewFieldValue(fieldIndex, value, checkForRefetch, true);

Posts: 65
Joined: 07-Dec-2005
# Posted on: 27-Dec-2005 16:02:30   

Thanks, I'm aware of that. However, I need to override that master function, rather than one of the shortcut overloads, since that master function is what is called by the actual entities.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39760
Joined: 17-Aug-2003
# Posted on: 27-Dec-2005 16:37:01   

AdamRobinson wrote:

Let me preface this by stating that I understand the philosophical difference between an empty string and null (in the database world). However, with what we're dealing with, they're essentially the same. Is there a way to specify, aside from changing my usage code, that an empty string assignment to a string column should be saved as a null in the database?

Add an IEntityValidator implementing object to the entity, and in the Validate method, check if the value is "", if so, set the field's value to null. Do this only if the field's IsChanged flag is set.

Frans Bouma | Lead developer LLBLGen Pro
Posts: 65
Joined: 07-Dec-2005
# Posted on: 27-Dec-2005 16:46:26   

Thanks, Otis. However, if I remember reading the docs right (and I may not!), the validator is only used when the entity is being persisted, right? If so, that's not going to work for me. I would actually like to perform this sort of thing when the property is actually set, hence my desire for an override.

Is that something that is out of the question?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39760
Joined: 17-Aug-2003
# Posted on: 27-Dec-2005 17:20:37   

AdamRobinson wrote:

Thanks, Otis. However, if I remember reading the docs right (and I may not!), the validator is only used when the entity is being persisted, right? If so, that's not going to work for me. I would actually like to perform this sort of thing when the property is actually set, hence my desire for an override.

True, the validation is performed when you save the entity. Though you don't have to do anything for the other situations, because the default value for a string property which is null, is "", so if you set the field to null, and you read the field again, you'll get "".

Frans Bouma | Lead developer LLBLGen Pro
Posts: 65
Joined: 07-Dec-2005
# Posted on: 27-Dec-2005 17:25:39   

From our previous conversations, I'm using a custom PropertyDescriptor for all of my bindings so that I will indeed get a null value rather than your default value. That is precisely why I'm experiencing the problem I'm having that I posted in my other thread in this forum.

So is it possible to have the function that does the actual work be overridable, rather than the pass-thru overloads? sunglasses

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39760
Joined: 17-Aug-2003
# Posted on: 30-Dec-2005 11:54:00   

AdamRobinson wrote:

From our previous conversations, I'm using a custom PropertyDescriptor for all of my bindings so that I will indeed get a null value rather than your default value. That is precisely why I'm experiencing the problem I'm having that I posted in my other thread in this forum.

So is it possible to have the function that does the actual work be overridable, rather than the pass-thru overloads? sunglasses

Not at the moment, no. A virtual method implies that it is replaceable, which it isn't. It's essential that that routine is called, so making it virtual isn't an option.

Frans Bouma | Lead developer LLBLGen Pro
Posts: 65
Joined: 07-Dec-2005
# Posted on: 30-Dec-2005 16:14:22   

I disagree. Virtual imples that the function is mutable. While that "mutation" could certainly include replacement, look at all of the "On<EventName>" virtual methods in .NET. I don't think the implication here is to REPLACE the functionality of the event raising method. The intent is to allow the developer to modify the way the method works. If that modification includes the removal of the call to base, well then the fault of any problems lies in the hands of the developer.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39760
Joined: 17-Aug-2003
# Posted on: 30-Dec-2005 17:03:58   

AdamRobinson wrote:

I disagree. Virtual imples that the function is mutable. While that "mutation" could certainly include replacement, look at all of the "On<EventName>" virtual methods in .NET. I don't think the implication here is to REPLACE the functionality of the event raising method. The intent is to allow the developer to modify the way the method works. If that modification includes the removal of the call to base, well then the fault of any problems lies in the hands of the developer.

Then we disagree on this simple_smile . Some say every method should be virtual so the developer is free to extend whatever he wants (whichis the default in java) , others disagree with that and argue that if you do that, behavior of the class can be unexpected and that's undesired. I'm in the last camp.

However, I thought of some other workaround: you could use a different typeDefaultValue*.template file in your template set, and set the default there to null, for the string instead of string.empty or "". Then a string property always returns null when the value is indeed null.

Frans Bouma | Lead developer LLBLGen Pro
Posts: 65
Joined: 07-Dec-2005
# Posted on: 30-Dec-2005 20:00:10   

That's true. However, my issue was not in GETTING the property (my PropertyDescriptor handles that piece of logic), but in SETTING it. When I set it, I want null instead of "", and in order to do that I have to change the functionality of your method. I have accomplished this, but it doesn't properly polymorph, since I'm just doing a "new" (aka "shadows" in vb) on the method.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39760
Joined: 17-Aug-2003
# Posted on: 30-Dec-2005 21:10:53   

But SETTING it is done for which reason? THe framework by itself doesn't need it. So your code needs it. Which is outside the framework and thus works with the result of the getter. Or am I missing something?

Making the method virtual just because you wrote software in a given way isn't the way to go IMHO, as then I can better make every method virtual and I then get complaints that a virtual method is slower (which it is) than a nonvirtual method.

As a last resort, you can write a type converter, which converts from string to string and converts "" to null and null to "".

Frans Bouma | Lead developer LLBLGen Pro
Posts: 65
Joined: 07-Dec-2005
# Posted on: 30-Dec-2005 21:16:40   

I don't really need to continue arguing. If you can't make a code change that is 100% backward compatible, then I guess you can't make the change. The issue with setting it is I want a null in the database instead of an empty string.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39760
Joined: 17-Aug-2003
# Posted on: 30-Dec-2005 22:19:49   

AdamRobinson wrote:

The issue with setting it is I want a null in the database instead of an empty string.

I then think that a type converter would solve it, as that's used to convert values from one type to the other for database persistence and back, so you can convert "" to null and back. The typedefaults indeed don't help you, as that is the other way around, which is thus not good advice from my part, I didn't understand the problem clearly.

Frans Bouma | Lead developer LLBLGen Pro
Posts: 65
Joined: 07-Dec-2005
# Posted on: 30-Dec-2005 23:18:07   

Wouldn't that require that I place a typeconverter on every single field that I wanted to have this functionality?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39760
Joined: 17-Aug-2003
# Posted on: 31-Dec-2005 00:23:17   

AdamRobinson wrote:

Wouldn't that require that I place a typeconverter on every single field that I wanted to have this functionality?

Naah simple_smile You can use a type conversion definition and apply the filter to all string typed fields in one go using the plugin that's shipped with llblgen pro (right click 'Entities' and execute it) simple_smile Please consult the manual on type conversion definitions simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Posts: 65
Joined: 07-Dec-2005
# Posted on: 31-Dec-2005 08:06:41   

So...it sounds like the answer to my question is actually yes? You would have to apply a TypeConverter to every field that would implement this behavior. Yes, you have a plugin to assign the converters en-masse, but it's still a TypeConverter on every field. I have a hard time believing that this is going to be a better solution than having a virtual method, but we don't need to get back to that.

If you have other suggestions, I welcome them, but it looks like for now I'm going to be stuck with a slapdash solution to something pretty simple no matter which route I go.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39760
Joined: 17-Aug-2003
# Posted on: 31-Dec-2005 11:06:16   

(Edit) Ok, re-re-reading the thread, I think a type converter isn't what you want, as you need it at runtime, as an EntityValidator would be enough as well. I'll briefly explain below why I won't change the method's accessor:

AdamRobinson wrote:

So...it sounds like the answer to my question is actually yes? You would have to apply a TypeConverter to every field that would implement this behavior. Yes, you have a plugin to assign the converters en-masse, but it's still a TypeConverter on every field. I have a hard time believing that this is going to be a better solution than having a virtual method, but we don't need to get back to that.

If you have other suggestions, I welcome them, but it looks like for now I'm going to be stuck with a slapdash solution to something pretty simple no matter which route I go.

It's a situation I've been before and in those situations I did change the API during a production release, and it turned out bad. The decision was made to not change the api on fundamental elements of a production release.

The thing is: you want behavior that's not supported. I can do two things: - alter the code so it is supported - offer you a workaround

Altering code so it is supported is a wide area. Making the method virtual now helps YOU but it also implies I can never make it non-virtual again unless it breaks someone's code. A guideline for making methods virtual is that you have an example to override it. This particular method is very important. It does a couple of things, like checking if the field has to be set, and then setting it. It's therefore KEY this code is executed. Overriding it CAN apply this code isn't run, which means a risk is run to alter framework code. So I won't make this change. Not now, not tomorrow. A better solution is to alter the code in such a way that it is extensible and it has methods which are there to be overriden by users, like the various On... methods.

That requires a redesign of the code and we don't do that on production code, only on new code.

So what's left is a workaround. You might not like it, but it's what I can offer you.

The other reason I have against changing the code is that I have to change code so it will meet your way of solving a GUI related problem. I don't think that we should do that, simply because a change (whatever that change may be) should be there to make the framework better, not offer a solution to a problem which has multiple solutions and isn't related to the framework: if you store null instead of "" in the field, nothing has to be changed. If you want to do that behind the scenes without any effort, you can do that via a typeconverter. The route you took: altering templates for the entities, is more complex and can lead to a lot of overhead code for you to maintain. Also a reason why simple changes at first look the great solution but turn out to be not the great solution.

To recap, I'd like you to take a step back and explain in full why you need 'null' instead of "" at runtime. If it's just for the propertydescriptors, you can add code there to solve it. If it's for other code, I'd like to understand why that other code needs it too. For persistence, you can use an entityvalidator or a typeconverter to change "" to null.

At the moment the necessity for the null instead of "" at runtime is not clear to me. If you like working with null strings instead of empty strings, that's your choice, but believe me: your code is better of with empty strings than with null values as strings, that is: in memory.

Frans Bouma | Lead developer LLBLGen Pro
Posts: 65
Joined: 07-Dec-2005
# Posted on: 31-Dec-2005 14:47:24   

Like you said, it looks like we simply disagree on this issue. I can agree that you should at least have an example of WHY you want to override the code (which I have given), but your assertion that the example must represent something that is as "key" as the code in the original method doesn't match up with what I see, at least not in the .NET framework. What about SetBoundsCore or SetVisibleCore on a control? Are those not key? Overriding these methods and not calling the base's would lead to undesired and unexpected results. But they're overridable anyway. Why? Because the situation exists where the INPUT to these methods may or may not be the exact input that this particular control wants. Perhaps this control should always be in the bottom right hand corner, no matter what the user says. Unless you're able to override this CORE method, where all of the other pass-thru methods like Left, Top, Width, Height, Location, and Bounds all converge, you're left with the undesirable job of overriding the pass-thru's, keeping track of any new ones that develop (maybe MS decides to put in X and Y; you have both Left and X, and Top and Y on the rectangle class, why not controls?), and you still may not get all of them (what if it's docked? I doubt MS goes through these pass-thru methods).

Would it be detrimental to the functionality of the framework if someone were to override this code and not run the base? Sure, that's entirely possible. Is it your responsiblity to make sure that they do? No. The core methods and the On methods serve entirely different purposes.

If you want to make an extensible set of tools to allow people to insert themselves into the line of what is being set into a field, that's fine. What I'm saying is that you really don't need it if you even have the slightest level of confidence in the users of your library. If people don't understand that overriding something is a big deal, then they will when it dies on them.

This is not a "GUI problem". My GUI is just fine right now. What I want is how it's stored in the database. Your library is not the only system that accesses this data, and to purport that an emtpy string is "just as good" as null is hardly true. Null has a meaning, which I'm sure you're aware of. Empty string is empty string. However, in many fields, an empty string in THAT context is contextually equivilant to null (no data; undefined; unknown; etc), so when there exists a usable value that means this in EVERY context and not just this one, it makes sense from a maintenance perspective to use this value. DBA's know what null is. They know what an empty string is too, and they know it's not null. They don't know that when column_one is emtpy that it's pretty much the same as null, they know it's an empty string. I want to remove this confusion and store MY data in the way that I define.

As for a level of code maintenance, I'm not really seeing how having a master entity class that all of my generated entities inherit from presents an issue of maintenance, especially given the other alternatives offered. I have a central point where all of this code goes (just as you do), that does a quick step and passes it off to your method. The only difference is that mine cannot be a proper implementation until it polymorphs. Will it work? Yes. Will I ever experience a situation where I MUST reference one of my entities as an EntityBase or IEntityBase and call SetNewFieldValue? Highly doubtful. I don't have the IDE in front of me, but I would suspect that that method is protected anyway, but perhaps not. But I would much rather have something that CAN'T fail, rather than something that WON'T fail.

I understand your position, and I recognize that we apparently disagree at a fundamental level on what is a virtual method and where it should exist. Should you make every virtual like Java? Certainly not. Should you make a method virtual when a user demonstrates a desire and a plausible justification for why a particular method should be? I think so, you don't. That's fine, it's your code. But as you recognized, none of the workarounds you've listed are workable, so I'm going to have to stick with mine. It works, it's 90% clean (just doens't polymorph), and provides a central location for me to change this functionality without having to regenerate my entire DAL.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39760
Joined: 17-Aug-2003
# Posted on: 31-Dec-2005 16:07:57   

AdamRobinson wrote:

Like you said, it looks like we simply disagree on this issue. I can agree that you should at least have an example of WHY you want to override the code (which I have given), but your assertion that the example must represent something that is as "key" as the code in the original method doesn't match up with what I see, at least not in the .NET framework.

I didn't make that up, Brad Abrams did, who is in charge of writing the guidelines for MS.

What about SetBoundsCore or SetVisibleCore on a control? Are those not key? Overriding these methods and not calling the base's would lead to undesired and unexpected results. But they're overridable anyway. Why? Because the situation exists where the INPUT to these methods may or may not be the exact input that this particular control wants. Perhaps this control should always be in the bottom right hand corner, no matter what the user says. Unless you're able to override this CORE method, where all of the other pass-thru methods like Left, Top, Width, Height, Location, and Bounds all converge, you're left with the undesirable job of overriding the pass-thru's, keeping track of any new ones that develop (maybe MS decides to put in X and Y; you have both Left and X, and Top and Y on the rectangle class, why not controls?), and you still may not get all of them (what if it's docked? I doubt MS goes through these pass-thru methods).

I'm not sure what you're trying to argue here. I explained my position, and that's it.

Would it be detrimental to the functionality of the framework if someone were to override this code and not run the base? Sure, that's entirely possible. Is it your responsiblity to make sure that they do? No. The core methods and the On methods serve entirely different purposes.

Yes it is my responsibility that they do that because if something is KEY to the framework, it is code which has to be ran. The SetNewFieldValue overloads which are virtual are virtual because they have to be extended through generated code. If that necessity wasn't there, the methods wouldn't be virtual (as they were in earlier versions).

We try to make those routines virtual which we think would be possible extension points to our customers. It's not you who has to give support to developers who come in and ask questions because their code stops functioning. So it's us who decides what we think is good for our customers to override and which code they should stay away from. This routine is one of those routines.

This is not a "GUI problem". My GUI is just fine right now. What I want is how it's stored in the database. Your library is not the only system that accesses this data, and to purport that an emtpy string is "just as good" as null is hardly true. Null has a meaning, which I'm sure you're aware of. Empty string is empty string. However, in many fields, an empty string in THAT context is contextually equivilant to null (no data; undefined; unknown; etc), so when there exists a usable value that means this in EVERY context and not just this one, it makes sense from a maintenance perspective to use this value. DBA's know what null is. They know what an empty string is too, and they know it's not null. They don't know that when column_one is emtpy that it's pretty much the same as null, they know it's an empty string. I want to remove this confusion and store MY data in the way that I define.

please don't lecture me on what the difference between "" and NULL means, I know that. The framework is very clear on what to do when you want NULL being inserted into a field in updates/inserts.

If you want NULL when the user specifies "", that's your BL rule, not something of the framework, that's why I said 'gui-related problem', i.o.w.: the layer calling the DAL code decides what's correct data: a "" or a NULL.

I offered you a workaround with an entityvalidator which at save time converts "" into null. This wasn't good enough for you as you needed it at runtime too. That won't work as the properties check for null and return the default instead (which is "").

You may store the data in the way you define, in fact you should. What frustrates me to the bone is that there's no workaround good enough: I have to make the method virtual, everything else is apparently a bad solution.

We're still arguing that because I refuse to do that. What I fail to understand is why the workaround of the entityvalidator doesn't work for you, as it is perfectly capable of saving null for "" without you writing a lot of code or having to insert a class above entitybase.

As you use selfservicing, you could also use an include template and override every string property in the derived entity class, using the include template, though that would give more generated code, while an entityvalidator is pretty simple.

As for a level of code maintenance, I'm not really seeing how having a master entity class that all of my generated entities inherit from presents an issue of maintenance, especially given the other alternatives offered. I have a central point where all of this code goes (just as you do), that does a quick step and passes it off to your method. The only difference is that mine cannot be a proper implementation until it polymorphs. Will it work? Yes. Will I ever experience a situation where I MUST reference one of my entities as an EntityBase or IEntityBase and call SetNewFieldValue? Highly doubtful. I don't have the IDE in front of me, but I would suspect that that method is protected anyway, but perhaps not. But I would much rather have something that CAN'T fail, rather than something that WON'T fail.

When a template change occurs you have to update your templates too. That's what I meant by code maintenance. You have to keep the templates with your project. Extending existing code through include templates for example would be easier. Or an entityvalidator to get it correctly inserted into the DB when you save.

I understand your position, and I recognize that we apparently disagree at a fundamental level on what is a virtual method and where it should exist. Should you make every virtual like Java? Certainly not. Should you make a method virtual when a user demonstrates a desire and a plausible justification for why a particular method should be? I think so, you don't. That's fine, it's your code. But as you recognized, none of the workarounds you've listed are workable, so I'm going to have to stick with mine. It works, it's 90% clean (just doens't polymorph), and provides a central location for me to change this functionality without having to regenerate my entire DAL.

Well, if you think I should make a change just because you think it's plausible, you should take a step back and consider that whatever we change will not only affect YOU but also thousands of other customers and their applications. You're not the only one working with the code, Adam.

I presented a workaround which DOES work (2 actually) for the purpose of saving "" as NULL into the db without you having to alter any calling code.

Earlier in this thread you said this wasn't good enough. It's still not clear to me WHY rage : if the field's CurrentValue is null, reading the property will return "", not null. This is because working with null as 'NULL' isn't supported for LLBLGen Pro on .NET 1.x, even though a string is a reference type and can be null: working with null instead of "" is causing more problems than it solves and therefore "" is returned as default value when the field is null.

Not your problem? Override the property in an include template in the derivedentity template.

But that's actually besides the point, because "" == NULL == null in your application, as "" results in NULL so NULL is equal to "". Which makes me clearly wonder why at runtime you also need null instead of "", if both are representing semantically the same value.

Frans Bouma | Lead developer LLBLGen Pro
1  /  2