Enforcing unique rule during ValidateEntityBeforeSave

Posts   
 
    
pat
User
Posts: 215
Joined: 02-Mar-2006
# Posted on: 22-Feb-2009 02:30:12   

Hi,

I have a table like this: PrimaryKeyID, ProjectID, TypeID, Name 1,1,1,Test1 2,1,1,Test2 3,1,2,Test1 3,1,2,Test1 <- WRONG

Now the Name column needs to be unique per TypeID for some ProjectIDs but not for others..

It seems like the best place to enforce this is in the ValidateEntityBeforeSave event. To make sure it works the check should be within the same transaction which is saving the entity.

The problem is that no database connection is passed into ValidateEntityBeforeSave so I was wondering on how to implement it?

Thanks, Patrick

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 22-Feb-2009 19:31:06   

IMHO, the best solution is place a Unique constraint at DB-side (your table). This way you can catch the error if the combination already exist in data. This also is better for concurrency scenarios.

David Elizondo | LLBLGen Support Team
pat
User
Posts: 215
Joined: 02-Mar-2006
# Posted on: 22-Feb-2009 22:43:24   

daelmo wrote:

IMHO, the best solution is place a Unique constraint at DB-side (your table).

Sure but if you imagine a system which can have multiple projects and some projects have that unique constraint while others don't... Then it becomes a business rule which needs to be checked in the BL / DAL...

How would I validate the scenario above with LLBLGen please?

Thanks, Patrick

Walaa avatar
Walaa
Support Team
Posts: 14993
Joined: 21-Aug-2005
# Posted on: 23-Feb-2009 10:07:53   

Selects doesn't have to be within a transaction. This also doesn't prevent you from raising an exception from within the validator class to stop any current running transaction.

But if you insist on having this select inside the same transaction, then this should be done outside the Validation code.

Simce this is a Business rule I suggest you have a BL method (say: "SaveItem") where you create a transaction and query the database for a matching name, and if it doesn't exist you proceed with the save.

pat
User
Posts: 215
Joined: 02-Mar-2006
# Posted on: 24-Feb-2009 03:21:14   

Hi Walaa,

thanks for answering... Here some comments:

Walaa wrote:

Selects doesn't have to be within a transaction.

How can you guaranty that another transaction isn't just inserting the same name into the unique column without e.g. using IsolationLevel.RepeatableRead?

Walaa wrote:

But if you insist on having this select inside the same transaction, then this should be done outside the Validation code.

Why should this be outside the validation code? Isn't the validation code meant exactly for this?

Walaa wrote:

Simce this is a Business rule I suggest you have a BL method (say: "SaveItem") where you create a transaction and query the database for a matching name, and if it doesn't exist you proceed with the save.

This wouldn't work if I'm saving a graph without a lot of work of cycling through every element in the graph....Also what would happen if that same entity is saved through another method as part of another graph?

It still seems like the best option would be to have the connection available in the validation code.

Thanks, Patrick

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 24-Feb-2009 07:54:13   

Hi Pat,

As I see, there are muliple validation levels (see this ) ... (not necessarily in order):

  1. Validation which deal with just a single field of one entity, for example a value for an ID field may not be less than 0. In this section, this is called Field validation.

  2. Validation rules which work with multiple fields of a single entity, for example the shipping date of an order can't be earlier in time than the orderdate itself. In this section, this is called Entity validation.

  3. Business logic rules which deal with multiple entities, for example a customer is a gold customer if the customer has more than n orders in the last m months.

  4. DB-side schema that enforce data integrity (have to do with normalization, for example).

  5. GUI validation, that ensures the user put the right values at front.

  6. Validate that the employee in charge of using the system, go to work simple_smile

You get the point. The thing is that LLBLGen implements the 1, 2 and part of the 3, the other is up to you. IMHO, in a stateless persistence scenario the logic that validate an Entity object should be aware of the data inside that entity. The other kind of validations should be done somewhere else. But other people can talk better on this subject than me wink

David Elizondo | LLBLGen Support Team
pat
User
Posts: 215
Joined: 02-Mar-2006
# Posted on: 25-Feb-2009 03:13:41   

daelmo wrote:

The thing is that LLBLGen implements the 1, 2 and part of the 3, the other is up to you.

It's up to me to implement but it's up to the framework to provide options for it...

pat wrote:

It still seems like the best option would be to have the connection available in the validation code.

So I would prefer to discuss if this is a good option and if it is I would appreciate if: a) we discuss how to accomplish this b) that there is consideration to add it to the LLBLGen feature wish list

Thanks, Patrick

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39859
Joined: 17-Aug-2003
# Posted on: 25-Feb-2009 11:40:40   

pat wrote:

Hi,

I have a table like this: PrimaryKeyID, ProjectID, TypeID, Name 1,1,1,Test1 2,1,1,Test2 3,1,2,Test1 3,1,2,Test1 <- WRONG

Now the Name column needs to be unique per TypeID for some ProjectIDs but not for others..

It seems like the best place to enforce this is in the ValidateEntityBeforeSave event.

Unique in what context? The data in memory, or All data (data in memory + data in the db) ? If the latter, this will not work, as you otherwise have to lock the entire table: there always can be a user which inserts a value in a new row in the same table on a different thread (asp.net website, or other desktop installation) which will break the save anyway because a UC fails.

Frans Bouma | Lead developer LLBLGen Pro