IDataError

Posts   
1  /  2
 
    
pilotboba
User
Posts: 434
Joined: 05-Aug-2005
# Posted on: 18-May-2006 23:57:34   

Can you expand a bit on the IDataError interface?

First of all, what namespace is this in... I couldn't find it in the docs?

Am I expected to call SetEntityFieldError in the validate code, or does this happen automatically.

Then what, do I cast the Entity to IDataError to get the stuff? The tool tip said you can access it with IDataErrorInfo[index] but what class is that an indexer of?

Thanks, BOb

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 19-May-2006 08:38:20   

IDataError is a .NET interface from the system.componentmodel namespace (if I'm not mistaken). It's basicly used by grids and the like AND the errorprovider control you can drag onto a form simple_smile .

As explained in the preliminairy docs, field overflow checks do set the error for a field, though you can do too in a validation method. The indexer is in IDataError.

Frans Bouma | Lead developer LLBLGen Pro
pilotboba
User
Posts: 434
Joined: 05-Aug-2005
# Posted on: 16-Jun-2006 21:23:21   

Otis wrote:

IDataError is a .NET interface from the system.componentmodel namespace (if I'm not mistaken). It's basicly used by grids and the like AND the errorprovider control you can drag onto a form simple_smile .

As explained in the preliminairy docs, field overflow checks do set the error for a field, though you can do too in a validation method. The indexer is in IDataError.

Ok,

I just don't get it. Perhaps you can give me some sample code.

How do I set the error string for a property of the index?

So, if in the field validation of the entity what code? If I try:


((IDataInfoError)this)["City"] = "City can not be blah blah";

It tells me I can't set the read only value?

Also, if I try to do this in my test:


AddressBookEntity addbook = new AddressBookEntity();

addbook.City = "Orlando";

Assert.AreEqual("", addbook.City);
Assert.AreEqual("City blah blah", ((System.ComponentModel.IDataErrorInfo)addbook)["City"] );

I get an error of "Entity validator returned false." Which I assume the default class is populating. How do I put my own error message there?

Also, the .Error property seems to be empty.

Also, why do I have to cast to the interface to access the indexer and Error property? I guess thought they are alway available?

What I want to do, is in field validation code set the error message for a certain property. Then I the UI layer (ASP.Net) I want to be able to read the error message(s).

Help!

BOb

pilotboba
User
Posts: 434
Joined: 05-Aug-2005
# Posted on: 16-Jun-2006 21:47:57   

Ok,

I'm making some progress here. I found the SetEntityFieldError() method and passed it the value... I set it a false to not append. But, now the string for the property contains:

Orlando is not a valid city.;Entity validator returned false.

So, it looks like the default behavior appened the message to my message. Is it supposed to do that.

Also, when I put a valid value into the property it looks like the Error message is not cleared. Is it up to me to clear it? I would expect if the field validation passes that the entitybase class would clear out the error?

The other thing, where there is an error in a property then .Error still returns nothing. Shouldn't it return the agreegate of all the error message, or is that considered a seperate error item?

BOb

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 17-Jun-2006 10:58:01   

pilotboba wrote:

Ok,

I'm making some progress here. I found the SetEntityFieldError() method and passed it the value... I set it a false to not append. But, now the string for the property contains:

Orlando is not a valid city.;Entity validator returned false.

So, it looks like the default behavior appened the message to my message. Is it supposed to do that.

Yes, the default does an append. IDataError is really a retarted interface: it can only READ values (so I had to add the methods you were unable to find in your previous message) and there's just 1 error per key. So to be able to store more than one error message, I added an append feature. You can use an overload of SetEntityFieldError() which accepts a boolean which allows you not to append but to overwrite the error message.

Also, when I put a valid value into the property it looks like the Error message is not cleared. Is it up to me to clear it? I would expect if the field validation passes that the entitybase class would clear out the error?

Yes, at the moment you've to clear it because you also set it. Your point is however food for thought. I'm a little undecided in this though: it would be great if it was reset automatically, however on the other hand, what if someone wants to keep the errors for checks later on (not using IDataError for display purposes for example), or better: wants to control when the errors are overwritten?

Though I'll file an issue about this so it pops up for the next build to think about. I do control the moment when the value is written so I do know when to clear the error message. The entity error however isn't cleared automatically.

The other thing, where there is an error in a property then .Error still returns nothing. Shouldn't it return the agreegate of all the error message, or is that considered a seperate error item?

I'm not certain what you mean by error in a property, could you give an example?

Frans Bouma | Lead developer LLBLGen Pro
pilotboba
User
Posts: 434
Joined: 05-Aug-2005
# Posted on: 19-Jun-2006 19:09:33   

Otis wrote:

You can use an overload of SetEntityFieldError() which accepts a boolean which allows you not to append but to overwrite the error message.

But, even if I pass false, the default message is still getting populated. I really only want my message(s) in there.

BTW: There is no overload, you have to always pass the bool.

Otis wrote:

Yes, at the moment you've to clear it because you also set it. Your point is however food for thought. I'm a little undecided in this though: it would be great if it was reset automatically, however on the other hand, what if someone wants to keep the errors for checks later on (not using IDataError for display purposes for example), or better: wants to control when the errors are overwritten?

Well, if you are using this for what it is designed for, the Winforms data provider. My understanding is that as soon as the user types the correct value into the field you want the erorr indicator (! thing) to go away. If you need leave the error message there, it won't.

I can clear the error message, but it seems to me that this should be the default. Also, I can't remove the key from the hashtable, I can only clear the string.

It seems to me if someone wants to keep the error messages then THAT should be the time you need to add code, since this is the more exceptional behavior. You could possibly add an OnFieldErrorChanging() method to deal with this. However, I can already intercept the error message in my field validator code.

Otis wrote:

I'm not certain what you mean by error in a property, could you give an example?

The IDataErrorInfo interface has two members:

The indexer (Item) member. And the Error member. The Error members description in help is "Gets an error message indicating what is wrong with this object."

In your implementation you are treating the errors in the Item collection seperatly from the value that the Error Method returns. But, my expectation is that Error() would return the addregate of all the messages in the Item collection. I would test this with a DataSet but I don't know how to use them in a way that a business rule would populate a value in the IDataErrorInfo member. wink

BOb

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 20-Jun-2006 11:02:34   

pilotboba wrote:

Otis wrote:

You can use an overload of SetEntityFieldError() which accepts a boolean which allows you not to append but to overwrite the error message.

But, even if I pass false, the default message is still getting populated. I really only want my message(s) in there.

I think I indeed went a little overboard with these. I think by just logging overflow messages which are caught by the entity's own validation routine (which checks if a string is inside the set bounds of the field for example) are enough. In the case of such a failure, the call will never reach the validator anyway, as the value is already rejected.

BTW: There is no overload, you have to always pass the bool.

true, I didn't check the signature simple_smile

Otis wrote:

Yes, at the moment you've to clear it because you also set it. Your point is however food for thought. I'm a little undecided in this though: it would be great if it was reset automatically, however on the other hand, what if someone wants to keep the errors for checks later on (not using IDataError for display purposes for example), or better: wants to control when the errors are overwritten?

Well, if you are using this for what it is designed for, the Winforms data provider. My understanding is that as soon as the user types the correct value into the field you want the erorr indicator (! thing) to go away. If you need leave the error message there, it won't.

Good point. I'll see that I can change this.

I can clear the error message, but it seems to me that this should be the default. Also, I can't remove the key from the hashtable, I can only clear the string.

I'll change it that it will remove the key when the input is null or empty.

It seems to me if someone wants to keep the error messages then THAT should be the time you need to add code, since this is the more exceptional behavior. You could possibly add an OnFieldErrorChanging() method to deal with this. However, I can already intercept the error message in my field validator code.

indeed, seems like unnecessary code to me to add.

Otis wrote:

I'm not certain what you mean by error in a property, could you give an example?

The IDataErrorInfo interface has two members:

The indexer (Item) member. And the Error member. The Error members description in help is "Gets an error message indicating what is wrong with this object."

In your implementation you are treating the errors in the Item collection seperatly from the value that the Error Method returns. But, my expectation is that Error() would return the addregate of all the messages in the Item collection. I would test this with a DataSet but I don't know how to use them in a way that a business rule would populate a value in the IDataErrorInfo member. wink BOb

I don't see it as the aggregate of the field errors, that's why there's also a SetEntityError method. The (stupid) docs of IDataErrorInfo say only that it is an error message, not that it should aggregate the errors of the fields.

All in all it illustrates perfectly why this interface is silly, but people requested it, so I added it.

You made some good points and I'll make the changes. Not the last one about the Error property though.

Frans Bouma | Lead developer LLBLGen Pro
pilotboba
User
Posts: 434
Joined: 05-Aug-2005
# Posted on: 20-Jun-2006 15:23:27   

Otis wrote:

You made some good points and I'll make the changes. Not the last one about the Error property though.

Thanks.

Since the Items indexer only has string indicies, can you think of some generic way that my UI (web page) can get a list of all the error messages, without needing to know all the property names? I was planning on calling the Error method. But, that doesn't seem feasible now.

BOb

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 20-Jun-2006 15:40:10   

That would extend the interface IDataErrorInfo... This is also why it's so stupid: it doesn't offer a Count property to illustrate how many items with errors there are...

Frans Bouma | Lead developer LLBLGen Pro
pilotboba
User
Posts: 434
Joined: 05-Aug-2005
# Posted on: 20-Jun-2006 17:35:53   

Otis wrote:

That would extend the interface IDataErrorInfo... This is also why it's so stupid: it doesn't offer a Count property to illustrate how many items with errors there are...

Right, this is why I wanted you to change the IDataErrorInfo.Error implementation to return all the errors since you can iterate the Items indexer. Unless there is a way I am not aware of.

But, since you don't want to do that, I guess I will have to add that to my template. However in EntityBase2 IDataErrorInfo.Error is not virtual. Also, _dataErrorInfoErrorsPerField is private.

BOb

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 20-Jun-2006 17:44:39   

Would it help if I add a GetEntityFieldErrorList method? I also could add a method which returns the # of stored field errors...

Frans Bouma | Lead developer LLBLGen Pro
pilotboba
User
Posts: 434
Joined: 05-Aug-2005
# Posted on: 20-Jun-2006 18:31:44   

Otis wrote:

Would it help if I add a GetEntityFieldErrorList method? I also could add a method which returns the # of stored field errors...

Anything that lets me get all the field errors so I can display them on the web page would be a help.

BOb

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 20-Jun-2006 18:48:21   

Ok, I'll add such a method.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 21-Jun-2006 11:58:17   

It sucks. IDataErrorInfo is implemented explicitly, to make sure that the methods are used in the context of IDataErrorInfo. This means that you've to do: IDataErrorInfo errorInfo = (IDataErrorInfo)entity;

Now, whatever I add, it's not available. So you then have to cast to something else again to get access to that property. That's bad, as it's bad design: you then use another type to access data which is solely the property of IDataErrorInfo. I already find the Set.. error methods a thing which I don't want, but it's necessary as the IDataErrorInfo interface is designed to be read-only.

As I see it, the IDataErrorInfo is solely meant to be used with the error provider control in winforms databinding scenario's and the indexer is IMHO used for simple databinding scenario's e.g. textbox.text bound to textproperty (but I don't know for sure).

GAAHH.. I wished I'd never added this crappy interface.

So: stuck. I can't add the messages to the main error, as I then have to add english text, which isn't what the user wants. I can't add a method as that causes casting crap and type definition badness.

Frans Bouma | Lead developer LLBLGen Pro
pilotboba
User
Posts: 434
Joined: 05-Aug-2005
# Posted on: 21-Jun-2006 19:34:03   

Otis wrote:

It sucks. IDataErrorInfo is implemented explicitly, to make sure that the methods are used in the context of IDataErrorInfo. This means that you've to do: IDataErrorInfo errorInfo = (IDataErrorInfo)entity;

Now, whatever I add, it's not available. So you then have to cast to something else again to get access to that property. That's bad, as it's bad design: you then use another type to access data which is solely the property of IDataErrorInfo.

Right, my thought was to hide your .Error() implementation and inset my own using your GetEntityFieldErrorList method or such. Actually, probably be just as easy if you make the _dataErrorInfoErrorsPerField collection protected.

Because, I want this in the IDataErrorInfo interface so my UI layer can support it whether the page uses an EntityBase2 or a DataSet or DataRow or whatever.

"Explicitly Implemented"

Is this why I can't access the index or the Error() method directly from the Entity, I always have to cast it?

Otis wrote:

As I see it, the IDataErrorInfo is solely meant to be used with the error provider control in winforms databinding scenario's and the indexer is IMHO used for simple databinding scenario's e.g. textbox.text bound to textproperty (but I don't know for sure).

Yes, I agree. The indexer is for simple errors (bound to a textbox) and the Error() method is for grids, it shows one error per grid. This is what I think the Error() method should return a single string which is all of the indexer strings concatenated togther seperated by a delimiter (semi-colon perhaps).

BOb

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 21-Jun-2006 20:31:30   

pilotboba wrote:

Otis wrote:

It sucks. IDataErrorInfo is implemented explicitly, to make sure that the methods are used in the context of IDataErrorInfo. This means that you've to do: IDataErrorInfo errorInfo = (IDataErrorInfo)entity;

Now, whatever I add, it's not available. So you then have to cast to something else again to get access to that property. That's bad, as it's bad design: you then use another type to access data which is solely the property of IDataErrorInfo.

Right, my thought was to hide your .Error() implementation and inset my own using your GetEntityFieldErrorList method or such. Actually, probably be just as easy if you make the _dataErrorInfoErrorsPerField collection protected.

That's what I have in mind now: create a protected property which returns this collection. It somewhat mitigates the set methods as you can use the construct returned by the property also to set data, but c'est la vie wink

"Explicitly Implemented"

Is this why I can't access the index or the Error() method directly from the Entity, I always have to cast it?

Yes.

Otis wrote:

As I see it, the IDataErrorInfo is solely meant to be used with the error provider control in winforms databinding scenario's and the indexer is IMHO used for simple databinding scenario's e.g. textbox.text bound to textproperty (but I don't know for sure).

Yes, I agree. The indexer is for simple errors (bound to a textbox) and the Error() method is for grids, it shows one error per grid. This is what I think the Error() method should return a single string which is all of the indexer strings concatenated togther seperated by a delimiter (semi-colon perhaps).

I toyed with that idea too, but it then makes the Error property useless for direct error reporting, you then always have to format.

Ok, I'll add the protected property ,you then can generate a method into the entities if you want which grab the whole dictionary and have fun simple_smile

Frans Bouma | Lead developer LLBLGen Pro
pilotboba
User
Posts: 434
Joined: 05-Aug-2005
# Posted on: 21-Jun-2006 20:33:05   

Frans,

Here's how "I" would request that you change this:

  1. Remove the _dataInfoError field.
  2. Remove the SetEntityError() method.
  3. Implement IDataErrorInfo.Error as follows:

string IDataErrorInfo.Error
{
     get 
     {
        StringBuilder sb = new StringBuilder();
        foreach (KeyValuePair<string, string> kvp in _dataErrorInfoErrorsPerField)
        {
           sb.Append(kvp.Value + ";");
         }
         return sb.ToString();
      }
}

This way I can use the Interface. I can get a specific error for a property or I can get all the errors for the whole entity.

If you won't do this, at least make IDataErrorInfo.Error virtual so I can override it.

BOb

BertS
User
Posts: 89
Joined: 28-Jul-2005
# Posted on: 21-Jun-2006 22:51:56   

pilotboba wrote:

Frans,

Here's how "I" would request that you change this:

  1. Remove the _dataInfoError field.
  2. Remove the SetEntityError() method.
  3. Implement IDataErrorInfo.Error as follows:

string IDataErrorInfo.Error
{
     get 
     {
        StringBuilder sb = new StringBuilder();
        foreach (KeyValuePair<string, string> kvp in _dataErrorInfoErrorsPerField)
        {
           sb.Append(kvp.Value + ";");
         }
         return sb.ToString();
      }
}

This way I can use the Interface. I can get a specific error for a property or I can get all the errors for the whole entity.

If you won't do this, at least make IDataErrorInfo.Error virtual so I can override it.

BOb

I think that is not the way to go, because it is not how .Error is meant. The indexer is not only useful for individual controls, but also within grids. With the indexer, the cell that has the error is marked, while the .Error only the row marks.

Frans, about the casting: in 2004.1 I've modified the templates to implement IDataErrorInfo, which works fine. I never needed to cast somewhere.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 22-Jun-2006 11:27:40   

BertS wrote:

pilotboba wrote:

Frans,

Here's how "I" would request that you change this:

  1. Remove the _dataInfoError field.
  2. Remove the SetEntityError() method.
  3. Implement IDataErrorInfo.Error as follows:

string IDataErrorInfo.Error
{
     get 
     {
        StringBuilder sb = new StringBuilder();
        foreach (KeyValuePair<string, string> kvp in _dataErrorInfoErrorsPerField)
        {
           sb.Append(kvp.Value + ";");
         }
         return sb.ToString();
      }
}

This way I can use the Interface. I can get a specific error for a property or I can get all the errors for the whole entity.

If you won't do this, at least make IDataErrorInfo.Error virtual so I can override it.

I think that is not the way to go, because it is not how .Error is meant. The indexer is not only useful for individual controls, but also within grids. With the indexer, the cell that has the error is marked, while the .Error only the row marks.

That was exactly what I was thinking as well, and why I have made two methods to set error messages: one for .Error and one for the individual cells. So the bound control knows where to find the error message and IDataErrorInfo is solely ment for that purpose. It's still sad it's a limited interface, but that's life.

Frans, about the casting: in 2004.1 I've modified the templates to implement IDataErrorInfo, which works fine. I never needed to cast somewhere.

True, I could have implemented it right in the entity's interface, but I refused to do that as that suggests it's part of the entity's interface, but it's part of the IDataErrorInfo interface.

@pilotboba: I think you want to use IDataErrorInfo for general error reporting for an entity, not directly related to databinding. I think IDataErrorInfo isn't meant for that and it therefore falls flat on its face. I'll add a protected property to the class, so you can add your own interface to the entities and use the internal bucket for the error messages.

Frans Bouma | Lead developer LLBLGen Pro
pilotboba
User
Posts: 434
Joined: 05-Aug-2005
# Posted on: 22-Jun-2006 16:15:06   

Otis wrote:

@pilotboba: I think you want to use IDataErrorInfo for general error reporting for an entity, not directly related to databinding. I think IDataErrorInfo isn't meant for that and it therefore falls flat on its face. I'll add a protected property to the class, so you can add your own interface to the entities and use the internal bucket for the error messages.

Well, I want to way to display the field validation errors to the user. That is related to binding.

As I said, if you make the Error() property virtual and the _dataErrorInfoErrorsPerField protected I can just override it in my templates, get what I want without you changing your implementation of IDataErrorInfo.

Also, can you enhance "SetEntityError();" to allow for appending a message like you do for SetEntityFieldError()?

I sill haven't worked on my UI classes, but I wanted to be able to simulate the error provider that WinForms have in my web page. I wanted to be able to use the interface so the UI classes would support dataset and datarow as well as entitybase2 objects. I think makeing the visibility changes requested in this message I can do this.

Other than that, any ideas would be appreciated.

BOb

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 23-Jun-2006 12:09:18   

pilotboba wrote:

Otis wrote:

@pilotboba: I think you want to use IDataErrorInfo for general error reporting for an entity, not directly related to databinding. I think IDataErrorInfo isn't meant for that and it therefore falls flat on its face. I'll add a protected property to the class, so you can add your own interface to the entities and use the internal bucket for the error messages.

Well, I want to way to display the field validation errors to the user. That is related to binding.

As I said, if you make the Error() property virtual and the _dataErrorInfoErrorsPerField protected I can just override it in my templates, get what I want without you changing your implementation of IDataErrorInfo.

As it's for web, which doesn't know IDataErrorInfo, why don't you implement your own interface? After all, you're now trying to bend IDataErrorInfo into something it's not designed for and which could have been solved with a new interface for the purposes you need? You can let llblgen pro generate the interface definition into the classes, and simply add the code through an include template or through generated partial classes. You could store the error info right into your validator classes so you don't have to jump through hoops.

Also, can you enhance "SetEntityError();" to allow for appending a message like you do for SetEntityFieldError()?

Read it, append text, set it again. simple_smile

Frans Bouma | Lead developer LLBLGen Pro
pilotboba
User
Posts: 434
Joined: 05-Aug-2005
# Posted on: 23-Jun-2006 16:15:01   

Otis wrote:

As it's for web, which doesn't know IDataErrorInfo, why don't you implement your own interface?

Because when I create a winform UI layer for my domain model I wan't the data binding/error provider to be able to access the iterface.

Otis wrote:

After all, you're now trying to bend IDataErrorInfo into something it's not designed for and which could have been solved with a new interface for the purposes you need?

No, I want to use it for EXACTALLY what it was designed for, to retrieve the "data object's" error messages.

I don't understand why making the visibility/virtual changes I am requesting is such a problem? Normally you are very accomodating. Your implementation stays exactally the same, and I can override it to work the way I want it to. I don't want to have to customize the ORMSupportClasses for this small thing.

BOb

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 23-Jun-2006 16:25:48   

What I want to avoid is the mistake I've made sometimes in the past (not for you, but in other occasions) where I made changes which later on turned out to be not that useful outside the scope of the application of the requester.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 27-Jun-2006 10:58:52   

There will be two protected properties: DataErrorInfoErrorsPerField (non virtual) which will return the Dictionary<string, string> of the errors per field and DataErrorInfoError (virtual) which will return the error for the entity. IDataErrorInfo will use the dictionary directly and will call the virtual property for the entity error. This gives you thus the freedom to create your own error message through overriding the property and also gives you the possibility to manipulate the field errors if you want to as well as access them in normal code.

Frans Bouma | Lead developer LLBLGen Pro
Posts: 5
Joined: 11-Sep-2006
# Posted on: 10-Oct-2006 21:48:39   

Have these properties created in the latest LLBL V2 ?

DataErrorInfoError and **DataErrorInfoError **

Do you have any VB.net example on how to use the IDataError and these two new properties ?

Thanks

1  /  2