Home
Help
Register
Log in

Search

 
   Active Threads  

You are here: Home > LLBLGen Pro > LLBLGen Pro Runtime Framework> Change empty string to null
 

Pages: 1
LLBLGen Pro Runtime Framework
Change empty string to null
Page:1/1 

  Print all messages in this thread  
Poster Message
JimFoye
User



Location:
Austin, TX
Joined on:
22-Jun-2004 04:03:11
Posted:
656 posts
# Posted on: 22-Oct-2007 00:41:26.  
Can I use OnSetValue to change an empty string to null? Currently I do this in CommonEntityBase, overriding OnValidateEntityBeforeSave():

Code:

protected override void OnValidateEntityBeforeSave()
{
base.OnValidateEntityBeforeSave();

// set any modified string fields that are "" to null
for (int i = 0; i < Fields.Count; i++)
{
     IEntityField2 field = Fields[i];
     if (field.IsChanged)
     {
         string s = field.CurrentValue as string;
         if (s != null && s.Length == 0)
             SetNewFieldValue(i, null);
     }
}
}


Which is a little inefficient, to say the least, but works well.

I tried

Code:

protected override void OnSetValue(int fieldIndex, object valueToSet, out bool cancel)
{
string s = valueToSet as string;
if (s != null && s.Length == 0)
     valueToSet = null;
base.OnSetValue(fieldIndex, valueToSet, out cancel);
}


and then

Code:

protected override void OnSetValue(int fieldIndex, object valueToSet, out bool cancel)
{
string s = valueToSet as string;
if (s != null && s.Length == 0)
{
     SetNewFieldValue(fieldIndex, null);
     cancel = false;
}
else
     base.OnSetValue(fieldIndex, valueToSet, out cancel);
}



but in both cases my current test in OnValidateEntityBeforeSave() still evaluates to true and I have to set it again.

Jim

  Top
daelmo
Support Team



Location:
Guatemala City
Joined on:
28-Nov-2005 23:35:24
Posted:
8094 posts
# Posted on: 22-Oct-2007 06:59:15.  
Hi Jim.

OnSetValue is called before the value is already set. So, after your code is performed the value ("") continues the process of be set.

A better place is OnSetValueComplete...

Code:
namespace Northwind.EntityClasses
{
    public abstract partial class CommonEntityBase
    {
        protected override void OnSetValueComplete(int fieldIndex)
        {
            if (this.Fields[fieldIndex].CurrentValue is string
                && this.Fields[fieldIndex].CurrentValue != null
                && this.Fields[fieldIndex].CurrentValue.ToString().Length == 0)
            {
                this.SetNewFieldValue(fieldIndex, null);
            }
            
            base.OnSetValueComplete(fieldIndex);        
        }
    }
}


Hope helpful Wink


David Elizondo
LLBLGen'ing (articles and code snippets) | linkedin | twitter
 
Top
JimFoye
User



Location:
Austin, TX
Joined on:
22-Jun-2004 04:03:11
Posted:
656 posts
# Posted on: 22-Oct-2007 20:42:57.  
Indeed, OnSetValueComplete() is exactly what I needed, thanks.
  Top
JimFoye
User



Location:
Austin, TX
Joined on:
22-Jun-2004 04:03:11
Posted:
656 posts
# Posted on: 24-Oct-2007 00:33:41.  
Whoops. That appeared to work on until I pasted in a large quantity of data from the clipboard. Then I got StackOverflowException in SD.LLBLGen.Pro.ORMSupportClasses.NET20.dll.




  Top
Otis
LLBLGen Pro Team



Location:
The Hague, The Netherlands
Joined on:
17-Aug-2003 18:00:36
Posted:
37694 posts
# Posted on: 24-Oct-2007 10:36:49.  
huh? The method either works or not, it doesn't depend on size if it dives in a loop or not, it shouldn't.

Is it possible for you to obtain some parts of the stack so I have an idea where it loops around?
Frans Bouma
LLBLGen Pro / ORM Profiler Lead Developer | Blog | Twitter
 
Top
JimFoye
User



Location:
Austin, TX
Joined on:
22-Jun-2004 04:03:11
Posted:
656 posts
# Posted on: 24-Oct-2007 22:21:07.  
Well, I thought this was pretty weird. I can import a bunch of data from a file and it has no problem, but I was testing some functionality to paste the same data from the clipboard, and that's when it blew up. The debugger cannot evaluate anything at that point.

Let me play with this a bit more and make sure I'm not doing something really stupid, and I will post with more info.


  Top
JimFoye
User



Location:
Austin, TX
Joined on:
22-Jun-2004 04:03:11
Posted:
656 posts
# Posted on: 24-Oct-2007 22:46:43.  
Well, it appears the obvious is happening, which is that calling SetNewFieldValue from within OnSetValueComplete results in another call to OnSetValueComplete, etc. At least, that is what is happening in this case. For some reason, seems like when I tried it the first time, it worked.

Does calling SetNewFieldValue() from within OnSetValueComplete() result in recursion? And if so, only sometimes or always?

Currently my code looks like this:

Code:

protected override void OnSetValueComplete(int fieldIndex)
{
IEntityField2 field = Fields[fieldIndex];
string s = field.CurrentValue as string;
if (s != null && s.Length == 0)
     SetNewFieldValue(fieldIndex, null);

base.OnSetValueComplete(fieldIndex);
}


BTW overriding ToString() for field object to return .Name might be cool.
  Top
JimFoye
User



Location:
Austin, TX
Joined on:
22-Jun-2004 04:03:11
Posted:
656 posts
# Posted on: 24-Oct-2007 23:03:06.  
In addition to the override in CommonEntityBase, I also override OnSetValueComplete in my entity class:

Code:

protected override void OnSetValueComplete(int fieldIndex)
{
base.OnSetValueComplete(fieldIndex);

if (fieldIndex == (int)TraceFieldIndex.Name)
{
     dataColumn.ColumnName = this.Name;
     dataColumn.Caption = this.Name;
}
}


When I call SetNewFieldValue() from within CommonEntityBase.OnSetValueComplete(), then OnSetValueComplete gets called in the subclass, and it in turn calls base.OnSetValueComplete(), resulting in recursion.

How can I safely set the string field so it emits NULL to the db in OnSetValueComplete()? Or should I go back to what I was doing before?



  Top
Walaa
Support Team



Location:

Joined on:
21-Aug-2005 16:03:48
Posted:
14549 posts
# Posted on: 25-Oct-2007 10:55:45.  
I think OnValidateFieldValue is the best place to do so.
  Top
Otis
LLBLGen Pro Team



Location:
The Hague, The Netherlands
Joined on:
17-Aug-2003 18:00:36
Posted:
37694 posts
# Posted on: 25-Oct-2007 11:52:50.  
Actually, there's a special method for this. (You realize there is too much functionality in a framework when you overlook a feature you've added yourself Embarrassed)

It's called PreProcessValueToSet, and it's in EntityBase(2). You simply override it in the commonentitybase and you get the field to set + the value to set passed in. You then simply set the parameter valueToSet to the value it has to become and THAT value is then used for further processing, e.g. validation, auditing etc. Regular Smiley

Calling SetNewFieldValue() from OnSetValueComplete causes recursion indeed, as OnSetValueComplete is called from SetValue, which is called from SetNewFieldValue Regular Smiley


Frans Bouma
LLBLGen Pro / ORM Profiler Lead Developer | Blog | Twitter
 
Top
luciusism
User



Location:
Arlington, VA, USA
Joined on:
02-Jun-2007 21:38:28
Posted:
119 posts
# Posted on: 23-Dec-2007 03:10:33.  
This is a very helpful thread. I just edited my CommonEntityBase.cs file adding the following and it worked perfectly!

Code:

#region Custom Entity code
// __LLBLGENPRO_USER_CODE_REGION_START CustomEntityCode

// LKK: Override method to convert empty strings to null
protected override void PreProcessValueToSet(IEntityField2 fieldToSet, ref object valueToSet)
{
    if (valueToSet is string && valueToSet != null && valueToSet.ToString().Length == 0)
    {
        valueToSet = null;
    }
    base.PreProcessValueToSet(fieldToSet, ref valueToSet);
}

// __LLBLGENPRO_USER_CODE_REGION_END
#endregion
  Top
JimFoye
User



Location:
Austin, TX
Joined on:
22-Jun-2004 04:03:11
Posted:
656 posts
# Posted on: 23-Dec-2007 18:24:37.  
luciusism, since you posted this, I hope you won't mind a couple of helpful suggestions on your code. If valueToSet is null, then the 'is' operator will return false when comparing to string (or anything else). Also, once you have determined valueToSet is a string, calling ToString() on it is not needed. So you could make your code a little more efficient. (See my code below).

It occurred to me since I decided to stick with OnValidateEntityBeforeSave(), maybe I should put my code up here with an explanation, in case it's helpful to anybody else in the future. I noticed that PreProcessValueToSet was getting called on everything when fetching from the database. So my final solution was to stick with OnValidateEntityBeforeSave(). I keep it in a partial class in my DAL project, along with other partial classes containing code I used to insert directly into the generated files, or else use custom templates for. Using partial classes is much cleaner, if you have a choice.

Here's the entire file, (with a couple of cosmetic name changes):

Code:

using System.ComponentModel;
using SD.LLBLGen.Pro.ORMSupportClasses;

namespace XXXXXX.XXX.DAL.EntityClasses
{
    public abstract partial class CommonEntityBase
    {
        protected override void OnValidateEntityBeforeSave()
        {
            // Genpro considers empty string to be semantically equivalent to null. In the db,
            // query results can be very different depending on whether a column's value is
            // NULL or set a zero-length string. To fix this, if a changed field currently has
            // an empty string, we "correct" that so that NULL in sent to db. I looked also at
            // PreProcessValueToSet(), but it gets called for every entity/field when a XXXX is
            // loaded from the db, so this seems the best place to do this.

            base.OnValidateEntityBeforeSave();

            foreach (IEntityField2 field in Fields)
            {
                if (field.IsChanged)
                {
                    string s = field.CurrentValue as string;
                    if (s != null && s.Length == 0)
                        SetNewFieldValue(field.FieldIndex, null);
                }
            }
        }
    }
}


This certainly may not be the final word on the subject!

I do think Frans should consider building this option into the designer somehow.

Jim

P.S. Not sure, but I believe the whole "" vs. NULL issue may be moot in Oracle. I'm using SQL Server.



  Top
luciusism
User



Location:
Arlington, VA, USA
Joined on:
02-Jun-2007 21:38:28
Posted:
119 posts
# Posted on: 13-Feb-2008 02:05:30.  
Quote:

luciusism, since you posted this, I hope you won't mind a couple of helpful suggestions on your code. If valueToSet is null, then the 'is' operator will return false when comparing to string (or anything else). Also, once you have determined valueToSet is a string, calling ToString() on it is not needed. So you could make your code a little more efficient. (See my code below).


Thanks for the input, don't mind at all. I was wondering why I did that, then I noticed that I had copied and pasted from daelmo's code snippet. Embarrassed

Thanks for the code reference, great input for the llblgen community.
  Top
luciusism
User



Location:
Arlington, VA, USA
Joined on:
02-Jun-2007 21:38:28
Posted:
119 posts
# Posted on: 22-Nov-2016 17:44:18.  
With breaking changes to PreProcessValueToSet, updated code for CommonEntityBase is below:

Code:

    protected override void PreProcessValueToSet(IFieldInfo fieldInfoOfFieldToSet, ref object valueToSet)
    {
            if (valueToSet != null && valueToSet is string && valueToSet.ToString().Length == 0) { valueToSet = null; }
            base.PreProcessValueToSet(fieldInfoOfFieldToSet, ref valueToSet);
    }



  Top
Pages: 1  


Powered by HnD ©2002-2007 Solutions Design
HnD uses LLBLGen Pro

Version: 2.1.12172008 Final.