|
Subject:
|
Code generator and some other things
|
|
Posted By:
|
Hyzac
|
Post Date:
|
9/22/2006 8:21:42 AM
|
Were there any codegenerator used to generate the classes in this book and in that case wich one? Can you consider the DAL in the examples in this book to be a light version of an O/R-mapper? Is the examples given in this book any good applying on more advanced databases and applications or is it simple code for simple functions?
|
|
Reply By:
|
Imar
|
Reply Date:
|
9/23/2006 5:21:46 AM
|
Hi Hyzac,
I used Visual Studio's Class Designer to generate most of the objects, properties and methods for the applications in my chapters.
I also used a small in-house code generator to generate parts of the data access layer code.
I don't think the concepts used in my book can be see as an O/R mapper. One of the characteristics of an O/R mapper is that code is generated automatically; it's also quite often updateable, either through regeneration of code, or dynamically at run-time.
I have used the code from the book in many applications, from very small to very large. So, it certainly works in larger real-world applications.
Cheers,
Imar --------------------------------------- Imar Spaanjaars Everyone is unique, except for me. Author of ASP.NET 2.0 Instant Results and Beginning Dreamweaver MX / MX 2004 Want to be my colleague? Then check out this post.
|
|
Reply By:
|
Hyzac
|
Reply Date:
|
9/25/2006 1:22:12 AM
|
Thanks for the answers and thanks for an excellent book.
|
|
Reply By:
|
Imar
|
Reply Date:
|
9/25/2006 1:25:18 AM
|
You're more than welcome....
Imar --------------------------------------- Imar Spaanjaars Everyone is unique, except for me. Author of ASP.NET 2.0 Instant Results and Beginning Dreamweaver MX / MX 2004 Want to be my colleague? Then check out this post.
|
|
Reply By:
|
Hyzac
|
Reply Date:
|
9/28/2006 7:13:32 AM
|
I have some followup questions on the subject wich might be a little bit out of the scope of the book. Regarding relationships:
Wich is the easiest way to handle relationship with the code that are used in the book? It seems that if you want to make a list of Contents in the CMS example and put it in a gridview you have to bind the content type column to its own datasource to get the text instead of the id. I've read http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/CustEntCls.asp this article and here they manage relationships by setting the property contenttypeid as a contenttype object if I were to use the database in the CMS example.
Does that mean that it would be enough with one datasource on a page to get all the information on an object? But it feels like this could produce some overhead since I might not need all the data in property-object. To solve this I've heard something called lazyloading but I can't find any good examples how to fix that functionality.
As I said, this might very well fall out of the scope of the book but it would be nice to get some professional opinion on the subject since I'm quite new to the oo-architecture.
|
|
Reply By:
|
Hyzac
|
Reply Date:
|
9/29/2006 8:51:52 AM
|
To make the previous post a little bit simpler: How do I print a list with all the contents in the Contenttable in a gridview wich still shows the contentype text in the column. In the book the contents is filtered by a dropdownlist and thus you can get the information from there.
To put it in a more extreme situation say I have a table that has a lot of foreign keys say 5. How do I solve that in a good performance way? Do I have to put 5 different objectdatasources on the page and called the Get function on every RowDataBound to get that items text or is there som easier way?
|
|
Reply By:
|
Imar
|
Reply Date:
|
9/30/2006 8:46:50 AM
|
Hi Hyzac,
Performance and design are indeed interesting issues that need to be dealt with here. In an SqlDataSource, things are simple. You just change the SQL statement to include the Description from the related table in the query and you're done. But, with the object design chosen in the CMS this won't work as the Content item only exposes a ContentTypeId, not a ContentType object or something like that.
There are a few approaches to this. One is indeed to fire a query for each and every item in the Grid. However, this feels weird, for both in the code you have to write and in the performance hit you have to accept.
An alternative is to give the Content class a ContentTypeDescription property (besides the ContentTypeId) that holds the Description of the ContentType. At load time the property is filled with the category name and later displayed in the Grid directly. Works fine, and doesn't give you the performance hit of scenario 1 but it still feels weird to store more or less duplicate data (not really, but still...)
Another approach is taken in chapter 12 - The Wrox Bugbase. Each Bug has properties like Status, Severity, Reproducibility etc. Instead of simply holding a number (the primary key), these properties are of type NameValue, an object that exposes the primary key (Id) and a user-friendly Description. The user sees the description, while the database uses and stores the Id.
In my opinion, this is a clean solution. You still store some sort of derived data (that is, the running code doesn't need the Description, it's only used for display purposes), but because it's contained in its own object, it's much cleaner.
One downside with this solution is with two-way databinding. ASP.NET has problems to use complex objects and their properties as properties in a databinding scenario. So, it's easy to bind, say, Bug.Title to a TextBox, but it requires manual code to work with something like Bug.Severity.Id and Bug.Severity.Description.
A bit of a long post, but hopefully it helps you in understanding the different options you have.
Cheers,
Imar --------------------------------------- Imar Spaanjaars Everyone is unique, except for me. Author of ASP.NET 2.0 Instant Results and Beginning Dreamweaver MX / MX 2004 Want to be my colleague? Then check out this post.
|
|
Reply By:
|
Hyzac
|
Reply Date:
|
10/2/2006 2:29:34 AM
|
Thanks for the answers. During my research to find a solution to the problem I've noticed that ASP.NET seems to have some problem with handling objects since I found quite a few O/r-Mappers and other things to help handling objects. But I want to keep it simple and I really like the code used in this book. I havent gone through all the chapters in the book yet but the next chapter I'm gonna look at is 12 to see the solution there. Thanks again.
|
|
Reply By:
|
Hyzac
|
Reply Date:
|
10/2/2006 4:43:59 AM
|
It's me again. Sorry for asking so much. The NameValue solution works excellent and solved a few of my problems but theres still some things I can't figure out. Say you wanted to get two or more values out of a related table, for instance the application description and the isActive value. How to do that? Where do I draw the line to create an object of a table and when not to?
Why I ask so many questions is that I like this code and trying to apply it on a bit larger database and to get the concepts on how this would work. As I see it the problem occurs when I have to large tables that are related to each other and where I want to get information from both to put in a list. Both these tables are used as objects. I understand that I can go far by using a sitestructure that only uses an object a time but if you have som tips on the problem it would be much appreciated.
|
|
Reply By:
|
Imar
|
Reply Date:
|
10/3/2006 2:23:34 PM
|
Hi Hyzac,
Don't worry about asking too many questions; that's the whole purpose of this forum, and especially if it's about a Wrox book... ;-)
Anyway, I think if you want to stick to OO principles, you reach the point where you change a simple property into an object pretty quick. Obviously, it all depends on your preferences, knowledge, database schema and so on, but there is nothing wrong about creating objects with properties that are other objects or even collection of those objects.
I recently designed and help develop a large and clean framework on top of a broken CRM system. From a high level perspective, the system deals with "simple", real world objects like a Person, an Organization and so on. Obviously, you can't give these objects properties like:ShippingAddressStreet
ShippingAddressHouseNumber
VisitAddressStreet
VisitAddressHouseNumber as the number of properties quickly becomes too large to manage in a logical way. So, we designed a number of other, smaller classes, like Address (with a Type, like Shipping and Visiting), a ContactRecord (for e-mail addresses, phone numbers and so on) and many other real world objects.
A Person or an Organization class then gets properties of these types, or even collections of these types, often in the form of a Generics list, like List<Address> or List (Of Address).
Some of these lists have smart properties, like a DefaultItem, that return specific items from the underlying collection. So, assuming a Person has a list of address records called Addresses and one of those items is marked as a default item, you could do something like this:myPerson.Addresses.DefaultItem.Street or myPerson.Addresses[0].Street
Additionally you could create and assign an address like this:Address myAddress = new Address();
myAddress.Street = "Some Street";
myAddress.HouseNumber = "Some Street";
myAddress.Type = AddressType.Shipping;
myPerson.Addresses.Add(myAddress); When you save the person with Person.Save() you look at the Addresses collection, see if it's dirty and if it is, you save the items in the database. You store each address in an Address table, and link the address to the person in an PersonAddress junction table. At load time (in a static Person.GetItem(someId) method for example), you do the reverse: look at the junction table, find all associated address records in the Address table and dump them in the Person's Addresses collection.
(These are all just examples; there are many other ways to accomplish the same thing, but hopefully you can see where this is going.)
This leaves you with a clean and easy to understand object model. Without much training, other developers should be able to understand and use this model.
Now databinding, on the other hand is, a bit trickier. It's easy to pass these complex objects from a DAL or Business Layer up to the presentation layer, but then what? Binding the main Person properties to a GridView is simple as well; the GridView will do this automatically when you bind it to a collection of Person objects. You should also be able to, say, display the Addresses in a nested Repeater for example with some databinding code in, again for example, a RowDataBound event.
I think two-way databinding is a lot trickier, or maybe even impossible. ASP.NET has serious problems in accessing these complex objects / properties. That is, it can set something like myPerson.FirstName for you, but it won't be able to set myPerson.Addresses[0].Street again based on a form variable.
One solution to overcome this is to use one-way databinding. You design a form that is capable of displaying the correct properties and collections for your object. When the Save button is clicked, you get another instance of the same object from the database, then overwrite relevant properties with new entries from the form, and save the item to the database. This additional call, that isn't needed in pure two-way databinding, is, IMO, well worth the cost. It does take additional round-trips to the database, but with increased flexibility.
You can do something like this to save a Person:Person myPerson = Person.GetItem(myId);
myPerson.FirstName = txtFirstName.Text;
Address myAddress = new Address();
myAddress.Street = txtStreet.Text;
myAddress.HouseNumber = txtHouseNumber.Text;
myAddress.Type = (AddressType) lstType.SelectedValue;
myPerson.Addresses.Add(myAddress); Again, just an example, but one that works for me. I am sure you have your own ideas and opinions that you want to want to blend in to this, together with opinions from co-workers or other resources, but hopefully this puts you a bit on track, inspiring you to create well-designed and easy to navigate object models and applications.
A bit of a long post again, but this is not easily explained in a few sentences.... ;-)
Cheers,
Imar --------------------------------------- Imar Spaanjaars Everyone is unique, except for me. Author of ASP.NET 2.0 Instant Results and Beginning Dreamweaver MX / MX 2004 While typing this post, I was listening to: She's Lost Control (12 inch) by Joy Division (Track 1 from the album: Heart And Soul (CD 2)) What's This?
|
|
Reply By:
|
Hyzac
|
Reply Date:
|
10/4/2006 2:37:07 AM
|
I can't thank you enough for taking the time to answer my questions. But heres still one thing that I can't figure out. Example:
object1
property object2() as object2
...
object2
property object1() as object1
property object3() as object3
...
If some of the properties in an object is reference of another object how will I keep it from loading the entire object hierachy. And say that you have a m-to-m relationship like in the example above where object1 has a property of object2 and object 2 has a property of object1. If you were to get a list of object1 then wouldn't you end up with quite a large amount of object2:s?
|
|
Reply By:
|
Imar
|
Reply Date:
|
10/5/2006 3:22:25 PM
|
It all depends on how and where you load your data....
If you create and fill all your objects in public constructors, then yes, you'll create this chain or tree of objects. You create one object that in turn creates one or more objects that in turn create even more objects. But, if this is what you need, then why not? Why not have the User object create a collection of Roles that each have a separate RoleDescription (in the form of a NameValue object for example). You may end up with 20 or 30 different objects, but that shouldn't be a problem.
If you expect a large tree, both in terms of depth and in terms of the number of records, then you need to be careful. Let's assume you model a Programmer class that has a Projects collection that holds all the projects a developer has worked on. Each project would have a Client property (or a Clients collection) that in turn have a ContactPersons collection. This means that by loading a single Programmer, you could end up with 30 projects, an additional 37 Clients and maybe another 100 address records, totalling up to 168 objects. Again, if you need it, you may be able to get away with it, but obviously there is some sort of turning point where memory consumption and performance (loading objects, firing queries and so on) is no longer acceptable.
One solution is to create a Load method that loads the data:Programmer myProgrammer = new Programmer();
// At this point, nothing has been loaded yet.
// But now we load data:
myPerson.Load(); As an alternative to an instance Load method, you could do the same with a static GetItem method.
To make the loading process a bit more fine-grained, you can create an overload that accepts a (custom) LoadTypes enum. For example:
myPerson.Load(LoadTypes.Trainings);
Then in Load you would only load the data for the requested part.
A final alternative is "lazy loading" which basically postpones getting the data until it's necessary. A simple example of a property could look like this:private List<Client> clients;
public List<Client> Clients
{
get
{
if (clients == null)
{
clients = GetClientsFromDatabase()
}
return clients;
}
set
{
client = value;
}
}Wether this works OK in a web app depends on the design. Sometimes, getting all data up front in one fell swoop (chunky calls) may give you better results that getting everything in little pieces (chatty calls). So, your mileage may vary.
Maybe it's time we make the discussion a little more concrete? Maybe you can describe the system you're designing in a bit more detail? It's easier to think about real world objects than about hypothetical object1 and object3 objects.... ;-)
Cheers,
Imar
--------------------------------------- Imar Spaanjaars Everyone is unique, except for me. Author of ASP.NET 2.0 Instant Results and Beginning Dreamweaver MX / MX 2004 Want to be my colleague? Then check out this post.
|
|
Reply By:
|
Hyzac
|
Reply Date:
|
10/6/2006 8:43:55 AM
|
The solution we're doing is to upgrade an old asp website to the new ASP.NET 2.0. Upgrade might be the wrong word since we're planning a whole new application. But what we have is a quite large database both in tables and data, 30+ tables and the size of the database is over 1GB. This is the ground we will build from an create our objects from. the core of the database is 4 to 5 tables wich represent Company, Person, Exhibitor, Project and Fair. All the other tables are connected or helps connects the main tables to each other wich means that there are connections between almost every table somehow. The main tables all have quite many columns, about 20+ each.
All this make for quite large and many objects and therefor the persormace issue is quite important. Since the database itself gets information from a few other places it's not an easy task to begin to change the database structure.
So what we want to be able to do in PL is for instance list all(or perhaps limit by a number) exhibititing companies on a certain project with company name and personname.
Tables include in this is: Exhibitor wich has a foreign key to Company, a foreignkey to Project, and is connected to Person with a ExhibitorPerson table. Company wich is connected to Exhibitor and Person, the fk is in the other tables. Project wich is connected to Company and Exhibitor, fk in the other tables. Person wich is connected to Company and to Exhibitor with ExhibitorPerson.
Then these tables connects to a whole lot of other tables and sometimes back to a table twice by som middletable.
So what I would like to do is something like this.
Dim Exhibitors as Exhibitor.GetListByProject(projid)
For each exhibitor in Exhibitors
Response.write(exhibitor.stand & " " & exhibitor.company.name & " " & exhibitor.person.name)
Next
But what I also want is to be able to filter the information on some random criterias, for instance in the listing above I would only want to get the persons that are tagged for maincontact in the ExhibitorPerson table.
Since there are values in the ExhibitorPerson table other than the exhibitor identification and Person identification do I make an object out of that table to or how will I get the information from there? and would that return in a code like this: exhibitor.exhibitorperson.person.name
A lot of things I want but since this is one of the first big projects I will build in this kind of way I have a lot of questions. And one of the questions is if it is worth all the time to figure out when there are free or cheap solution exsisting today, like Wilson O/R-mapper. But of course when you made it yourself you know the code and can keep it to the functions you really want/need. But I might need to study the subject a little bit more before taking on a big project like this so if you have any tips on books or sites that can provide me with code and information that would be nice.
|
|
Reply By:
|
Imar
|
Reply Date:
|
10/9/2006 2:06:05 PM
|
There are many ways to do what you want; all depending on actual design, database, preferences, knowledge and so on.
Personally, I wouldn't create something like this: exhibitor.exhibitorperson.person.name
I see the additional data in the junction table as relation properties. So, Exhibitor.Persons(0).Name would give you the name of the first person in the collection.
Where you store other relational data depends on your model. If a SignedUp data makes sense on a Person object, you could store it there. Otherwise, you could have a class that inherirs from Person (Clients, for example) that has all the Person stuff, plus some "relational fields, like SignedUp or whatever you have stored in your ExhibitorPerson table.
In addition to that, you can give the Person collection (e.g. a class that inherits from something like CollectionBase) some additional behavior. Instead of the usual suspects like Items and Add, you could create methods like GetTaggedPersons (or make it a property TaggedPerson). Then you could do something like this:Dim myExhibitors As List (Of Exhibitors) = Exhibitor.GetListByProject(projectId)
For Each myExhibitor in myExhibitors
Dim myPersons As List (Of Persons) = myExhibitor.GetTaggedPersons(someTag)
For Each myPerson in myPersons
' Do something with the person
Next
Next I am sure there must be many books about this subject, but I can't recommend one. Maybe others on this list have worked with books that describes these concepts and can recommend something? I'd be interested as well to see what's been written about this subject.
Also, consider using OR mappers. Although you may not know all of your code because you didn't write all of it, OR mappers can be very useful. If they generate good code, you don't even have to know how they operate internally; only how to use them.
Cheers,
Imar --------------------------------------- Imar Spaanjaars Everyone is unique, except for me. Author of ASP.NET 2.0 Instant Results and Beginning Dreamweaver MX / MX 2004 Want to be my colleague? Then check out this post.
|