Creating new objects

Posts   
 
    
kulki
User
Posts: 26
Joined: 20-Dec-2004
# Posted on: 20-Dec-2004 16:41:58   

Hi, I had another question. Say that I want to create a new User object which basically translates to an insert in the DB. I think the code you suggest is the following:

User user = new User(); //populate all properties of the user object

User.Save();

Say that the business rule is that UserId and FirstName is required field.

But my concern with your framework is that it allows you to create a user object which does not have all it values properly initialized. Say that FirstName is a required field and the programmer forgets to populate this field. In this case the only error I get is a runtime error. Also typically this code I just wrote will be in the Code Behind/Presentation Layer. I would like the GUI not to know anything about the business logic that the firstName is a required field. Wouldn't it be better to create a constructor of this form

User user = new User(UserId, FirstName)

This way a programmer cannot create a User object which is not properly intialized. I am not trying to say what you guys have done is wrong but I am just trying to understand your logic. thanks

Marcus avatar
Marcus
User
Posts: 747
Joined: 23-Apr-2004
# Posted on: 20-Dec-2004 17:17:08   

I'll refer you to the Manager Classes again here (http://llblgen.com/tinyforum/Messages.aspx?ThreadID=1892)... they have Create methods which take the minimum required fields as parameters. This ensures that the entity is properly constructed and all required fields are populated.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39752
Joined: 17-Aug-2003
# Posted on: 20-Dec-2004 17:35:38   

kulki wrote:

Hi, I had another question. Say that I want to create a new User object which basically translates to an insert in the DB. I think the code you suggest is the following:

User user = new User(); //populate all properties of the user object

User.Save();

Say that the business rule is that UserId and FirstName is required field.

But my concern with your framework is that it allows you to create a user object which does not have all it values properly initialized. Say that FirstName is a required field and the programmer forgets to populate this field. In this case the only error I get is a runtime error. Also typically this code I just wrote will be in the Code Behind/Presentation Layer. I would like the GUI not to know anything about the business logic that the firstName is a required field. Wouldn't it be better to create a constructor of this form

User user = new User(UserId, FirstName)

This way a programmer cannot create a User object which is not properly intialized. I am not trying to say what you guys have done is wrong but I am just trying to understand your logic. thanks

If you want to check this, you can implement IEntityValidator and add a validator object to the entity which validates teh fields when entity.Validate() is called, which is called when the entity is saved for example.

The method approach is not that great, as when you add a field later on, you have to alter all constructor calls. Better is to use properties to set fields. Indeed, if a programmer misses a mandatory field this will result in flaws, but that's the responsibility of the developer. If the developer doesn't save the entity it also doesn't work (to name a trivial example)

Frans Bouma | Lead developer LLBLGen Pro
Marcus avatar
Marcus
User
Posts: 747
Joined: 23-Apr-2004
# Posted on: 20-Dec-2004 18:14:54   

Otis wrote:

The method approach is not that great, as when you add a field later on, you have to alter all constructor calls. Better is to use properties to set fields. Indeed, if a programmer misses a mandatory field this will result in flaws, but that's the responsibility of the developer. If the developer doesn't save the entity it also doesn't work (to name a trivial example)

Yes I agree that changes to the DB will cause code to break which can be a pain, but then I prefer compile time breakages rather than run time... But I certainly take your point. simple_smile

kulki
User
Posts: 26
Joined: 20-Dec-2004
# Posted on: 20-Dec-2004 21:44:31   

Well thats why I personally don't like to have to call entity.Save(). I would much rather simply called UnitofWork.COmmit(). This way the developer does not need to track what objects need to be saved.

Also the way I think is that one should not be able to create objects which are not properly intialized. I would assume that if there is an object in memory then it is intialized.

kulki
User
Posts: 26
Joined: 20-Dec-2004
# Posted on: 20-Dec-2004 21:47:13   

Otis wrote:

If you want to check this, you can implement IEntityValidator and add a validator object to the entity which validates teh fields when entity.Validate() is called, which is called when the entity is saved for example.

The method approach is not that great, as when you add a field later on, you have to alter all constructor calls. Better is to use properties to set fields. Indeed, if a programmer misses a mandatory field this will result in flaws, but that's the responsibility of the developer. If the developer doesn't save the entity it also doesn't work (to name a trivial example)

Well the validator method is invoked only when the save method gets invoked. Which means that I could have an invalid object in memory until I call the Save method. Don't you think its a much cleaner solution not to have an invalid object at all.

Devildog74
User
Posts: 719
Joined: 04-Feb-2004
# Posted on: 20-Dec-2004 22:06:58   

Marcus wrote:

Yes I agree that changes to the DB will cause code to break which can be a pain, but then I prefer compile time breakages rather than run time... But I certainly take your point. simple_smile

I have found that the looser the coupling between the interfaces the better. So by having Controller.Save(entityToSave) you have a very loose coupling. I used to write very granular interfaces, i.e. Save(field1, field2, field3) but when using COM+ thats a deployment nightmare.

kulki wrote:

Well the validator method is invoked only when the save method gets invoked. Which means that I could have an invalid object in memory until I call the Save method. Don't you think its a much cleaner solution not to have an invalid object at all.

I was under the impression that if default values were specified at the database field level then when the save occurred the defaults would be used if not set in the entity, thus always ensuring that a proper object was saved in the event that the developer didnt fill in all fields.

Also, for that matter, IMO you are never going to be able to 100% cover all fields during object instanciation. For example, if the OrderTotal field depends on price and quantity about all you could ever do during instanciation is ensure that the field was = 0 if it was numeric.

Also, IMO at some point, your developers writing code for the middle tier will need to become familiar with the entities and their meaning and scope as it applies to the business / problem domain at hand.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39752
Joined: 17-Aug-2003
# Posted on: 21-Dec-2004 10:40:32   

kulki wrote:

Well thats why I personally don't like to have to call entity.Save(). I would much rather simply called UnitofWork.COmmit(). This way the developer does not need to track what objects need to be saved.

A developer always has to do that, because in 9 out of 10 times the developer has to deal with some sort of business logic layer which takes care of the business rules. And no, how fowler/evans want you to use BL, i.e. cram everyting inside the entity classes, is not the way to go in the long run, as you run into problems soon enough because BL is scattered all over the place and there is no clear connection between the functional design of the functionality and the actual implementation (which is recognized by Evans by his remark that there should be some sort of translation language for that (so instead of fixing the problem in the first place, a fix for a symptom of the problem is suggested... )). Fowler doesn't have this problem from his POV as he is in the XP/agile camp.

Also the way I think is that one should not be able to create objects which are not properly intialized. I would assume that if there is an object in memory then it is intialized.

An entity that's not in the database is not defined by definition. This is a key aspect of working with entities. Anyone who claims an entity exists whenever you've instantiated it, hasn't thought about a multi-user application that's spread over multiple machines (2 desktops, 1 server, or 2 or more webservers in a webfarm as examples)

Frans Bouma | Lead developer LLBLGen Pro
kulki
User
Posts: 26
Joined: 20-Dec-2004
# Posted on: 21-Dec-2004 18:51:12   

Otis wrote:

A developer always has to do that, because in 9 out of 10 times the developer has to deal with some sort of business logic layer which takes care of the business rules. And no, how fowler/evans want you to use BL, i.e. cram everyting inside the entity classes, is not the way to go in the long run, as you run into problems soon enough because BL is scattered all over the place and there is no clear connection between the functional design of the functionality and the actual implementation (which is recognized by Evans by his remark that there should be some sort of translation language for that (so instead of fixing the problem in the first place, a fix for a symptom of the problem is suggested... )). Fowler doesn't have this problem from his POV as he is in the XP/agile camp.

Well my main concern with calling Entity.Save() is that the GUI developer needs to know what objects have been modified in the first place. In a large complex project I don't think thats a valid assumption. But in my case I am willing to live with it.

Otis wrote:

An entity that's not in the database is not defined by definition.

Thats an interesting idea. I was wondering if there is any material you could direct me to where I can read about this. I do see your point, but in the extreme case that there is no DB are u suggesting that there can be no entities? I think that the only reasons we need a DB is because we don't have unlimited memory. In a hypothetical scenario with unlimited memory I would simply not use a DB and purely have objects in memory.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39752
Joined: 17-Aug-2003
# Posted on: 22-Dec-2004 10:18:29   

kulki wrote:

... Well my main concern with calling Entity.Save() is that the GUI developer needs to know what objects have been modified in the first place. In a large complex project I don't think thats a valid assumption. But in my case I am willing to live with it.

Since when does a developer not know which objects are changed if he does write the code to change the objects? And even then, a non-changed object is simply skipped by the engine so it's not that important.

Otis wrote:

An entity that's not in the database is not defined by definition.

Thats an interesting idea. I was wondering if there is any material you could direct me to where I can read about this. I do see your point, but in the extreme case that there is no DB are u suggesting that there can be no entities? I think that the only reasons we need a DB is because we don't have unlimited memory. In a hypothetical scenario with unlimited memory I would simply not use a DB and purely have objects in memory.

A database serves another role as well: the only central repository where the application state is stored. With multiple users on a system, there is just 1 core part of the complete application which is the same for all: the database.

An entity is the data in an entitydefinition implementation in the database: the data in a row in a table. An entity therefore isn't 'existend' when you fill an instance of an entity-representing class with some data, until you save it in the database. As was mentioned earlier: if you use a sequenced PK or you define defaults in the db, you don't get these values back until you save the entity (that is, the data). Read the concepts in the documentation for more details. Fowler/evans define entity as something outside the database, which IMHO is wrong, as that's a plain re-definition of a wellknown definition.

Frans Bouma | Lead developer LLBLGen Pro
kulki
User
Posts: 26
Joined: 20-Dec-2004
# Posted on: 23-Dec-2004 03:09:15   

Otis wrote:

Since when does a developer not know which objects are changed if he does write the code to change the objects? And even then, a non-changed object is simply skipped by the engine so it's not that important.

Well say that the GUI developer does not have access to the Business Objects. Its then entirely possible for the GUI developer not to know about objects which BL might create and not expose to the GUI. Say that when I change the the firstName of a user a new Log entity is automatically created and this object is not exposed to the GUI at all.

Now the GUI might have the following code. User user = new User("Otis"); user.FirstName = Frans; UnitOfWork uow = new UnitOfWOrk(); uow.AddForSave(user); uow.Commit(); Now how does the log entity add itself to the transaction?

Otis wrote:

An entity is the data in an entitydefinition implementation in the database: the data in a row in a table. An entity therefore isn't 'existend' when you fill an instance of an entity-representing class with some data, until you save it in the database. As was mentioned earlier: if you use a sequenced PK or you define defaults in the db, you don't get these values back until you save the entity (that is, the data). Read the concepts in the documentation for more details. Fowler/evans define entity as something outside the database, which IMHO is wrong, as that's a plain re-definition of a wellknown definition.

Well this gives rise the issue of inserts when the DB generates the Pkey. Say that you have a parent object as well as a child object which are both created. How do you handle the logic that parent must be first inserted, then the based on the PK of the parent update the child's FK and then insert the child? Do we write any code to support this feature or does OR mapper handle this.

kulki
User
Posts: 26
Joined: 20-Dec-2004
# Posted on: 23-Dec-2004 03:34:53   

Also in your opinion whats should be the right behaviour under the following circumstances.

a) I create a entity object using the follwing code: UserEntity user = new UserEntity(); String firstName = user.FirstName;

Just throw an exception?

b) Say that Email address is a not a required field i.e. EmailAddress is a nullable. In my architecture I ended up using a DateType called NullableString which BTW can be downloaded from sourceforge. But in the code generator it only produces a datatype called string and not NullableString. How do I update EmailAdress such that a null value is stored in the Database?

kulki
User
Posts: 26
Joined: 20-Dec-2004
# Posted on: 23-Dec-2004 03:42:15   

kulki wrote:

Also in your opinion whats should be the right behaviour under the following circumstances.

a) I create a entity object using the follwing code: UserEntity user = new UserEntity(); String firstName = user.FirstName;

Just throw an exception?

b) Say that Email address is a not a required field i.e. EmailAddress is a nullable. In my architecture I ended up using a DateType called NullableString which BTW can be downloaded from sourceforge. But in the code generator it only produces a datatype called string and not NullableString. How do I update EmailAdress such that a null value is stored in the Database?

I guess my follow up question would be is there a way for me to change the code generator so that nullable strings become NullableStrings instead of strings.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39752
Joined: 17-Aug-2003
# Posted on: 23-Dec-2004 09:38:09   

kulki wrote:

Otis wrote:

Since when does a developer not know which objects are changed if he does write the code to change the objects? And even then, a non-changed object is simply skipped by the engine so it's not that important.

Well say that the GUI developer does not have access to the Business Objects. Its then entirely possible for the GUI developer not to know about objects which BL might create and not expose to the GUI. Say that when I change the the firstName of a user a new Log entity is automatically created and this object is not exposed to the GUI at all.

Now the GUI might have the following code. User user = new User("Otis"); user.FirstName = Frans; UnitOfWork uow = new UnitOfWOrk(); uow.AddForSave(user); uow.Commit(); Now how does the log entity add itself to the transaction?

I completely miss the point of having a gui which can't communicate with BL objects.

Otis wrote:

An entity is the data in an entitydefinition implementation in the database: the data in a row in a table. An entity therefore isn't 'existend' when you fill an instance of an entity-representing class with some data, until you save it in the database. As was mentioned earlier: if you use a sequenced PK or you define defaults in the db, you don't get these values back until you save the entity (that is, the data). Read the concepts in the documentation for more details. Fowler/evans define entity as something outside the database, which IMHO is wrong, as that's a plain re-definition of a wellknown definition.

Well this gives rise the issue of inserts when the DB generates the Pkey. Say that you have a parent object as well as a child object which are both created. How do you handle the logic that parent must be first inserted, then the based on the PK of the parent update the child's FK and then insert the child? Do we write any code to support this feature or does OR mapper handle this.

No you don't have to do anything, the O/R mapper core takes care of this. You can save a graph from any point, even the lowest leave, and it is saved in teh right order. It doesn't matter if you setup the graph in the gui and pass it on to another layer or remoted service either.

kulki wrote:

Also in your opinion whats should be the right behaviour under the following circumstances. a) I create a entity object using the follwing code: UserEntity user = new UserEntity(); String firstName = user.FirstName;

Just throw an exception?

All fields have a default value, defined in TypeDefaultValue.cs/vb (or typeDefaultValue.template) which is returned in this case.

b) Say that Email address is a not a required field i.e. EmailAddress is a nullable. In my architecture I ended up using a DateType called NullableString which BTW can be downloaded from sourceforge. But in the code generator it only produces a datatype called string and not NullableString. How do I update EmailAdress such that a null value is stored in the Database?

See: "Using the generated code / Selfservicing (or adapter) / Using the entity classes -> Entities, NULL values and defaults". It's pretty straightforward.

NullableTypes is a library I'm aware of, but our code is not relying on 3rd party libs for functionality plus the types have to be pure .NET types, not some type in a 3rd party library because that gives problems in VB.NET.

Frans Bouma | Lead developer LLBLGen Pro