To do this, you simply click the option to add a data source to your project, point it to your database, and then add the tables, views, and stored procedures that you want to use.. Alth
Trang 3Rapid C# Windows
DEVELOPMENT
Visual Studio 2005, SQL Server 2005,
& LLBLGen Pro
Quickly Build Robust, Database-Driven Applications
Joseph Chancellor
© Joseph Chancellor 2006
Trang 4All rights reserved No part of this book may be reproduced, stored in a database of any kind, or
transmitted in any way, form, or means without consent of the author, except for brief quotations for reviews or articles.
The information in this book is provided without any express or implied warranty The author, publisher, and any distributor are not responsible for any damages or loss arising directly or indirectly from the use of this book.
Cover and Book Design: Joseph Chancellor
Visual Studio NET 2005, SQL Server 2005, ClickOnce, Visual C#, and IntelliSense are trademarks of the Microsoft Corporation.
LLBLGen and LLBLGen Pro are trademarks of Solutions Design.
Trang 5Table of Contents
1: Introduction 1
Commanding the Army 1
Prerequisites 2
O/R Mappers 4
Strongly-Typed Objects 5
Native Language Filter Construction 7
Strongly-Typed DataSets vs LLBLGen Pro 8
N-Tier Application Design 11
Stored Procedures, Inline, and Dynamic SQL 11
Data Type Conversion 14
Visual Studio Advantages 14
Summary 14
2: The O/R Mapper 17
Preparing the database 17
Our schema AdventureWorks 18
LLBLGen Pro Objects 18
Scanning the Schema 19
Creating Entities 21
Entity Options 22
Adding Views 26
Creating Typed Lists 28
Adding Stored Procedures 30
Self Servicing vs Adapter 31
One Class vs Two Classes 32
Generating the Code 34
3: Solution Setup 37
Creating the solution 37
Adding references 39
App.config settings 40
LLBLGen Pro Project Overview 41
4: MDI Parent Form 43
MDI Parent 43
5: Simple Forms 49
Calling a Stored Procedure 49
Alternative Approach Using Entities and Relationships 54
Using Typed Views 58
Using Views as Entities 63
Using Typed Lists 64
Summary 64
6: Search Form 65
Order Search Form 65
7: Edit Form 75
Entity Extensions 75
Form Layout 76
Saving Entity Data 81
Creating New Entities 82
Deleting an Entity 83
8: Validation 85
Trang 69: Transactions 95
Preparing for the Unexpected 95
Isolation Levels 97
10:Tuning 101
Enhancing Performance 101
SQL Server Profiler 101
LLBLGen Pro Tracing 105
Simple Prefetching 106
Complex Prefetching 107
Multi-threading 108
Code Cleaning 112
11:Deployment 115
Measure Twice, ClickOnce 115
Certificates 116
Strong Name Key 117
ClickOnce Configuration 117
Deployment 121
Installation 121
12:Regenerating Code 123
Inevitable Changes 123
Minor Changes 123
Major Changes 129
13:Appendix 1 133
14:Afterword 135
Trang 7“Never put off until run time what can be done at compile time.”
David Gries, Compiler Construction for Digital Computers
Commanding the Army
After a long and bloody fight for the territory of ancient China, Liu Bang finally prevailed over his rivals Born from a peasant family, Bang became the first emperor of the Han Dynasty Known as a bold and arrogant man, he discussed his recent military successes with his finest general.
“How many soldiers could a person like myself command?” the Emperor asked confidently.
“Your Majesty could command but 100,000 men” the general stated matter-of-factly.
“Then how about you?” the Emperor asked.
“In my case,” the general replied, “the more, the better.” The Emperor laughed with surprise.
“If that is so, then why are you my subject?” the Emperor asked.
“Your Majesty’s talent lies not in the commanding of troops,” the wise general replied “Your Majesty’s talent lies in the commanding of generals.”
As a software developer, you also command a vast army of systems and architecture with almost limitless possibilities.But unfortunately for the developer, the technologies change almost hourly Unlike the armies of yesterday, the code-warrior of today is likely to find his or her weapons obsolete and battle plans insufficient to face new challenges thatdid not even exist last week
The concept for this book arose from a set of new programming tools and techniques that are not yet widelyadopted in the developer community Much of the reason for this oversight is a lack of understanding, and it is theaim of this book to help correct that deficiency These tools are very similar to the Chinese general in the Han
Dynasty: they are ruthlessly effective at what they do, and with them you can literally save hours, days, and weeks ofdevelopment time and code maintenance Do not make the mistake of becoming a micro-managing Emperor: you donot need to do it all yourself You are not trying to directly command the most troops (or personally write the mostlines of code) You are trying to win the war! And you are about to take a major step forward
Through the exercises in this workbook, you will learn how to use C# with Visual Studio NET 2005, SQL Server
2005, and an invaluable tool called an O/R Mapper (in this case, LLBLGen Pro) to rapidly develop database-drivenapplications You will gain an understanding of the benefits of using these technologies and you will see the completeprocess from start to finish, including scanning the database schema, generating code, adding business logic, andbuilding the user interface We will also cover validation, transactions, performance tuning, multi-threading, anddeployment While there are books, websites, and documentation that cover all of these technologies individually, wewill aim in this book to demonstrate how they can be used together as a rapid and robust solution, giving the
developer a practical walk-through with a multitude of explanations, diagrams, and screenshots
There are countless other methods and languages that a programmer could use to meet his or her database
application needs However, the methods in this book are expedient and have been proven to work Judge for
yourself as we walk through building a Windows application together
1
Trang 8Who is this book for?
• Beginners who have some experience programming in C# and are familiar with basic programming
terminology
• Intermediate developers who want to learn new techniques to shorten their development time
• Technology strategists who are investigating this approach in order to choose a platform for a project
• Those who want to put together a quick-and-dirty proof of concept for a database-driven application
• Those who have some familiarity with SQL programming (You do not need to be an expert, but you do need
a basic understanding of the SQL syntax to use and understand the generated framework.)
• Those wishing to learn cutting edge development skills and techniques
• Small development teams Using these methods, even a single developer can make a powerful database-drivenapplication and deploy it to their organization in a short amount of time No large budget or department ofdevelopers required
Who isn’t this book for?
• Non-Windows developers
• Developers who are completely unfamiliar with object-oriented programming We are not going to explain allthe details of OOP and you may not understand the concepts or code if object-oriented programming iscompletely new to you
• Developers with no SQL programming experience While LLBLGen Pro will help you compensate for
weakness in SQL, you may have a difficult time understanding and using the framework to write queries ifyou have no understanding of SQL syntax Fundamentally, LLBLGen Pro is a wrapper (and more) for SQL,and knowing the basics will ensure that you can take full advantage of the tools
• Those who are so familiar with SQL that they think in stored procedures and refuse to learn new techniques You will want to avoid the temptation to just write a stored procedure instead of figuring out a way to use the
generated framework Like anything else, learning these new techniques takes time Be patient, and you willachieve the results you want
How to read this book
This book is a practical walk-through that will build a sample application—step-by-step—with directions,
screenshots, and code samples The book is intended to provide all the information necessary for a beginner to fullylearn and grasp the tools In order to gain maximum benefit, be sure to follow along with the sample application,performing the directions on your machine as explained in the text However, if you are an intermediate user morefamiliar with the underlying concepts, you may elect to simply read the chapters and examine the code samples untilyou understand what is presented Optionally, you can create your own project while reading through the book,using the concepts presented, and making substitutions where necessary to apply it to your database schema andmake it fit your application requirements
Prerequisites
In order to fully utilize this book, you will need:
Visual Studio NET 2005 (highly recommended)
Currently in full release as of November 2005, you can buy this software from Microsoft at
http://msdn.microsoft.com/howtobuy Visual Studio NET 2005 has a variety of versions and prices Look for a
version that includes C# and that allows you to develop class libraries and Windows applications (You can use older
versions of Visual Studio, but you will miss some of the newer, time-saving features Refer to Figure 1.1 for a detailed
2
Trang 9comparison of the versions of Visual Studio NET 2005 available and the versions which include the features
necessary to take full advantage of this book.)
SQL Server 2005 (or other compatible database required)
In this book we will be building database-driven applications with SQL Server 2005 Microsoft offers a variety of SQLServer products—including a limited version that is available for free—and developer versions that accompanyspecific versions of Visual Studio NET 2005
Please note that we will not be covering the creation of your database or designing your schema We are assumingthat you have already developed your database or already have a database available Instead of SQL Server 2000/2005,you can also use previous versions of SQL Server, Microsoft Access, Firebird, Oracle, or MySQL, and for the mostpart, the process will be the same Note, however, that SQL Server 2005 was used exclusively in the creation of thisbook Therefore, if you use other database applications, your results may vary
LLBLGen Pro (required)1
Version: 1.0.2005.1.
LLBLGen Pro is an O/R mapper This tool will take an existing database schema and generate a data access tier (andmore!) in a matter of seconds LLBLGen Pro is available from http://www.LLBLGen.com for about $270 USD (EUR229) and can be used by your entire development team Although the product is an extra item to purchase, it is aninvaluable tool for developers working with databases (a fully-functional 30 day demonstration version is also
available and will allow you to work through the exercises in this book) Keep in mind that there is a free version ofLLBLGen available, but we will not be using it because it uses stored procedures exclusively and only does a fraction
of what the current version will do The original version was entirely reengineered, rewritten, and released as
1) Please note that the products discussed in this book are recommended on their merit alone; the author is not employed by Solutions Design (the creators of LLBLGen Pro) or any other software company, and does not receive any kind of commission or compensation from any of these companies.
Trang 10LLBLGen Pro You will not be able to follow any of the code samples in this book without the retail version of
LLBLGen Pro
You may be asking yourself, “Aren’t those programs expensive? Why not do it by hand?” Our answer is “Theseprograms save time!” We prioritize speed (but not at the expense of reliability or maintainability) and, therefore,recommend to you that you consider how much time and energy these programs can save you and not only the prices
of the products Looking at the projects developed in this book will serve as a good example (Figure 1.2) While youcould write the same Windows application by hand without Visual Studio, the automation that Visual Studio affordscan be tremendous In our example application alone, about 68% of the code in the Windows application project isgenerated automatically Most of this code is written as elements in the GUI are configured visually; only 32% of thecode was completely written by hand And the differences are even more pronounced using LLBLGen Pro in theapplication’s class library, which contains the business logic and data access layer (these terms are discussed later) Inthis project, over 98% of the code is automatically generated What the developer adds by hand amounts to a mere1,139 lines of code—less than 2% (Keep in mind that this application is in the beginning stages of development, andthat for this reason you will be adding much more custom code.) Another benefit of the code written by Visual Studioand LLBLGen Pro is that it is well commented, well spaced, and easy to read, adding to the line count of generatedcode The main point here, however, is that with these tools you can take a great leap forward on Windows projectsand projects that use databases Automating repetitive code is a major part of rapid development, and it is worthpaying for
Now, let’s take a look at the other concepts and principles that make this method of development a desirablechoice
O/R Mappers
An O/R Mapper creates classes defining objects that correspond to the structure of your database Every row becomes
an entity and every table becomes an entity collection The fields of the database table become public properties of theentity object The framework also builds in constructors and other useful methods to find entity objects, set theirproperties, and save them back to the database with just a few lines of code
4
Figure 1.2 Lines of code generated/automated versus hand-coded in each project in this book
Figure 1.3 Two related database tables
Trang 11If you are unfamiliar with O/R Mappers, take a look at Figure 1.3 Here are two tables from a database The tables are
named Individual and AddressBook and you will notice a relationship between the two.
After running an O/R Mapper on this schema, you will get a class library that you can immediately begin
referencing in your projects To use a row from this database, you could write the following code in your project(Example 1.4)
Example 1.4 O/R generated code example
Let’s walk through this code step-by-step The code in Line 2 automatically retrieves the Individual record with an
IndividualID of 23 and loads it into a custom object called an IndividualEntity (this name comes from the original
table) As you can see in Line 3, all of the fields of the original table are properties that can be accessed and changed2
In Line 4, a related record in the AddressBook table was accessed and a property changed And in Line 5, you see how easy it is to save those changes back to the database Notice that all of these actions can be performed without writing
any other extra code by hand, anywhere else The generated code from the O/R Mapper handles all of the steps that you
would normally have to code yourself, saving you from having to:
• Find the database server
• Log in and open a connection to the database server
• Select the particular database containing the information you want
• Find the correct table
• Find the correct row
• Read all the values for that row
• Convert every type of value from its SQL data type into the NET data type while checking and handling thepossibility of a null value
• Present those values in a strongly-typed format, so the consumer knows exactly what kind of object to expect(string, integer, array, etc.) and there are no surprises at run-time
• Create a container to temporarily hold the values while they are being modified
• Retrieve data from another row in a related table
• Manage which values have changed and make appropriate INSERT’s, UPDATE’s, and DELETE’s in the
appropriate tables in the database to reflect those changes
• Close the connection
Whew! That’s a lot of time saved! And that’s just the beginning
For those who are not familiar with all of the aspects of programming, let’s elaborate on what it means to bestrongly-typed and why strongly-typed objects are so helpful to developers
Strongly-Typed Objects
A major feature of using an O/R Mapper to auto-generate your code involves the use of strongly-typed objects Instead
of exposing simple and generic properties and methods, your generated code should expose specific objects you willactually be using
To understand the advantages of working in this manner, consider this analogy When Bob goes home every dayfrom work, he puts his keys on the table, drops his briefcase on the floor, and heads straight to the kitchen to makehimself dinner Every day, Bob does the same thing: he grabs a frozen dinner from the freezer and pops it in the
2) More specifically, all columns in the table can be read and columns that are non-key, non-calculated fields can be changed These concepts are explained later.
5
Trang 12microwave Bob has performed these actions so often that he does not really think about doing them each day He justopens the freezer, grabs something, and sticks it in the microwave We could express this particular freezer-to-
microwave exchange in C# as the following:
whether he will find stuffed animals in the fridge, pop-tarts in the DVD player, or razor-sharp toys peppered along the
staircase Bob would be wise to check exactly what it is he is pulling out of the freezer before he sticks it in the
microwave Now here is the same code improved by using a more specific object
We have improved this code by using a FrozenDinner object Now, if we try to grab something from Bob’s freezer that
is not a FrozenDinner, we will get an error when we try to cast it We could improve this even further by checking the type of the object before we cast it and accounting for the possibility of a non-FrozenDinner object If we used the as
keyword instead of casting the object, we would eliminate the chance of a casting exception, but then we would need
to check for a null FrozenDinner object before trying to cook it
In the NET world, this kind of situation is very common when you access data from external sources One of the
more common objects you will use is a DataTable In NET, DataTable objects are wonderful objects and extremely flexible But when you read data from a database into a DataTable and you need to get specific with the contents of a particular field on a particular row, the NET framework only gives you an object of type … well … object A plain
object is about as generic as you can get, and the NET framework does this intentionally to give you maximum
flexibility But if you assume that that object is a string, and will always be a string, you are entering the world of
assumptions—and code that is built on assumptions is brittle and unpredictable If you accidentally change the name
of a column in your database or reverse the order of columns in a set of records, you are asking for trouble Minorchanges can doom your code, and the worst part is that you will not know things have gone wrong until your code isrunning and the code fails miserably simply because what you always assumed would be a string happened to be aninteger or a boolean
Now let’s return to Bob’s frozen dinner for a moment We would eliminate a lot of guessing and unnecessarily
complex code if the method that gave us the frozen dinner simply returned an object of type FrozenDinner and not an object of type object That would save us the trouble of casting it and accounting for all the possibilities of a non-
FrozenDinner object Consider this final version of C# code:
In the real world, our database solution might entail extending a DataTable and specifically defining the type of every
column It might also entail creating a custom class and writing methods that read the data from the database table
and add it to the properties of the custom class Repeating this process by hand, for every table, stored procedure, and
6
Trang 13view in your database, while a wonderfully effective programming practice, would take you the rest of your natural life.
Just consider how long it would take to manually write a new method for every kind of object Bob might possiblywant to take from his freezer Unfortunately, these painfully slow methods of development are very common Butthere are several ways to automate this process, which we will discuss in a moment
The other general principle related to strongly-typing worth mentioning is that compile-time errors are always
preferable to run-time errors And of course, having no errors is the most desirable! Until computers begin to write
their own code without human input there will always be errors of
one kind or another But not all errors are created equal
Compile-time errors, which arise during compilation, are easier to fix
because they happen 100% of the time If you have one of these,
you cannot compile your application no matter how many times
you try You must fix the problem before continuing On the other
hand, a run-time error which arises as the application is running
will compile 100% of the time, but may only occasionally throw an error while executing These kinds of errors are
harder to test and harder to catch because they are inconsistent and only occur when a particular function is called
and when specific conditions are met.
Now, consider the three different frozen dinner code examples mentioned earlier In the first example, we willnever get any kind of error when compiling or executing (which is good), but unfortunately for Bob’s household, wecould end up with strange items in the microwave (not good) In the second example we have prevented putting non-
FrozenDinner objects in the microwave We will have no compilation errors (good), but have a real chance of run-time
errors if the object in the freezer is not a frozen dinner (not good) In the last example we get the possibility of
compile-time errors if we code incorrectly (very easy to fix), no run-time errors (very good!), and still no strangeobjects in the microwave (what we hoped for) Although there are many ways to solve this problem, the third method
is the most reliable, error-free solution
Native Language Filter Construction
A new feature in the latest version of LLBLGen Pro is native language filter construction In past versions of LLBLGenPro, creating a SQL query programmatically required excessive verbosity, as you can see in Example 1.8 Each part of
a query in this example is represented by objects which must be instantiated and combined in ways that are notnecessarily intuitive nor easy to read While these early versions were effective, they demanded that the developer taketime to be completely comfortable with the syntax
PredicateExpression MyPredicate = new PredicateExpression();
MyPredicate.Add(AW.Data.FactoryClasses.PredicateFactory.CompareValue(
EmployeeFieldIndex.HireDate,ComparisonOperator.GreaterEqual,
HireDateAfter));
MyPredicate.Add(AW.Data.FactoryClasses.PredicateFactory.CompareValue(
EmployeeFieldIndex.SalariedFlag,ComparisonOperator.Equal,
true));
Example 1.8 Old way of creating predicates
In the newest version of LLBLGen Pro, however, queries can be constructed in an intuitive manner more consistentwith normal C# syntax Consider Example 1.9 , where the same predicate has been written in native language Theend result is more readable code and less time spent learning the syntax
1
2
3
IPredicate MyPredicate =
(EmployeeFields.HireDate >= HireDateAfter) &
(EmployeeFields.SalariedFlag == true);
Example 1.9 Creating predicates with natural language construction
Compile-time errors are always preferable to
run-time errors
7
Trang 14Native language filter construction in C# is a helpful and time-saving new feature in LLBLGen Pro, and throughoutthis book, we will use this technique in code examples.
Strongly-Typed DataSets vs LLBLGen Pro
Let's take a brief look at the code generating tools integrated into Visual Studio and how they compare to LLBLGen
Pro Visual Studio allows you to auto-generate a strongly-typed DataSet that mirrors your database’s schema As you
might expect, this approach takes existing data objects and extends them, specifying the columns and data typesexplicitly To do this, you simply click the option to add a data source to your project, point it to your database, and
then add the tables, views, and stored procedures that you want to use Visual Studio will generate an XSD file (Figure
1.10) that will contain descriptions of all the database objects and their properties
In Figure 1.11, you can see the Northwind database schema as viewed through the DataSet Designer in Visual
Studio Visual Studio will even add the relationships between the tables automatically
8
Figure 1.10 A strongly-typed DataSet in a C# Windows project
Figure 1.11 A look at the schema of a strongly typed DataSet
Trang 15To utilize this DataSet you can simply use a TableAdapter, which is an object that is used to retrieve data from the database in order to fill the DataSet If you open the XSD file in Notepad, you can see the underlying structure of the
DataSet (Figure 1.12) Notice that SQL statements are included in the description of this DataSet Each table
description contains the specific SQL statement necessary to perform a SELECT, INSERT, UPDATE or DELETEaction
Although both the LLBLGen Pro method and Visual Studio's strongly-typed DataSet objects are solutions that
provide a data access layer, they are fundamentally different approaches Let’s take a look at some of the reasons whyLLBLGen Pro is the more usable of the two methods
Strongly-typed DataSet advantages: Using strongly-typed DataSet objects is a good technique that implements a
number of our best practices First, you can quickly and easily reap the rewards of using strongly-typed objects and
have assistance in creating your SQL statements and stored procedures The strongly-typed DataSet also automates the
process of consuming the data in your C# code; thus, both the query-generating and consuming features save time
The custom DataSet can also be referenced across your projects, becoming a handy and reusable data access layer A
key advantage of this method over LLBLGen Pro is that you do not need any other third-party software: this
functionality is built into Visual Studio
Strongly-typed DataSet disadvantages: Users of strongly-typed DataSet objects encounter several setbacks, all of
which LLBLGen Pro helps address:
• Query limitation: This disadvantage stems from the fact that SQL statements used by strongly-typed DataSet objects are created when the DataSet is designed, not when it is used With LLBLGen Pro objects, however,
the SQL code is generated as the object is used You can find the SQL statements by looking inside the
DataSet's XSD file, but in looking through the code that LLBLGen Pro produces you will find no SQL
statements anywhere The LLBLGen Pro dynamic query engine for SQL Server creates the statements only
when the data is retrieved from the database Because the SQL statements are all created when the DataSet is
defined, if you need a new query that has not been defined in advance, you will always need to redesign your
DataSet by adding the new query before you can consume it elsewhere in your code With LLBLGen you can
create and consume the query in your C# code by using the LLBLGen Pro framework—all without changingthe underlying data layer You would only need to change your data layer (by regenerating your code) if youmade changes to your schema or you add a new type of database object
• Difficulty propagating schema changes: When you do make changes to your schema, strongly-typed
DataSet objects do not provide a built-in method for propagating schema changes to your DataSet definition
and updating your SQL statements You would need to delete the corresponding DataSet table,re-add it from
the database, and then re-create all of the custom SQL queries that you had defined for that table (since onlyone query is added by default) Fundamentally, there is no built-in way for Visual Studio to refresh your
DataSet schema with changes from your database's schema If you forget to drop and add each table that
changed, or refresh the list of columns that have new names or data types, your code will mysteriously begin
9
Figure 1.12 A peek inside a strongly-typed DataSet definition file
Trang 16to throw exceptions LLBLGen Pro makes it easy to bring those changes to your code without losing any ofyour customization In Chapter 12, you will see how LLBLGen Pro automatically scans your entire databaseand automatically makes the necessary changes to your project for you.
• Limited data layer functionality: In order to traverse many-to-many relationships between tables, DataTable
objects require you to use intermediate tables LLBLGen Pro allows you to traverse relationships between
Entities more easily than you can using DataTable objects You actually can traverse a many-to-many
relationship by skipping over the intermediate table—an action that is not possible with a strongly-typed
DataSet.
• No help with business logic layer: A strongly-typed DataSet does not help you with your business logic
layer LLBLGen Pro can optionally create a business logic layer shell that saves you the trouble of creating oneyourself We will use this method in our walk-through
• Requirement of adapters in order to get data: In order to retrieve data for your strongly-typed DataSet, you
must first create a TableAdapter object If you use the self-servicing template when generating LLBLGen Pro code, you do not need any extra object like a NET TableAdapter to retrieve data It is as if your DataRow
objects fill themselves with data automatically-and this means you have to write fewer lines of code
• No support for custom SQL queries: Even with the Visual Studio automated tools, you will still need to getyour hands dirty writing SQL: some queries are too complex to use Query Manager The LLBLGen Proframework allows you to generate complex queries and replace the logic of many stored procedures withoutwriting any SQL yourself
These features make LLBLGen Pro a compelling choice for database access But by now, you may be wondering toyourself, “If O/R Mappers are so great, why isn’t Microsoft using this approach?” In fact, Microsoft is working on
it right now Originally, Microsoft was developing a project they dubbed “ObjectSpaces,” which was a method ofrepresenting relational data as objects This project was eventually assimilated into new projects not yet completed3.One of those projects is named WinFS, which will contain technology that is similar to O/R Mappers Quentin Clark,the project management team leader for WinFS, stated in his blog, “We are in the process of building-out the nextversion of ADO.NET to have new features that provide a data model, object-relational mapping, and flexible queryinfrastructure The new data model is about entities, and the WinFS data model of Item types is built on that
model.”4 WinFS has been under development since 2002 and is currently in Beta 1 The final release date for WinFS is
uncertain, but it will certainly be after the next version of Windows (Vista) is released.
The other main project from Microsoft is named LINQ, which stands for Language INtegrated Queries According
to the Microsoft Developer Network LINQ is “a codename for a set of extensions to the NET Framework that
encompass language-integrated query, set, and transform operations It extends C# and Visual Basic with nativelanguage syntax for queries and provides class libraries to take advantage of these capabilities.”5 LINQ will allow thedeveloper to use queries written in C# statements against many different kinds of objects loaded into memory Thescope of this project is much wider than sorting relational data: LINQ commands can sort data regardless of itssource At the moment, it is impossible for the developer to accomplish this alone Most of the time sorting andfiltering operations are relegated to the database LINQ will allow many of those operations to occur in the C# codewhere the NET code is running instead of in the database where SQL Server is running LINQ will work with
LLBLGen Pro generated code and therefore will be of great benefit to the developer when it is finally released
In addition to LINQ, Microsoft is creating a project specifically aimed at relational data, called DLINQ DLINQ is
an O/R mapper for Microsoft that will generate classes corresponding to your database’s tables and will use lazyloading (or “deferred query execution,” in Microsoft’s terminology) to dynamically generate SQL to retrieve, modifyand delete data The DLINQ project is simply a light-weight, Microsoft-built O/R Mapper At the 2005 MicrosoftProfessional Developers Conference, Microsoft gave a demo of the project to attendees Because the DLINQ project isstill in development, it currently offers far fewer features than LLBLGen Pro and will probably require several moreversions before it has a similar set of features to what LLBLGen Pro has today
The good news is that you do not have to wait for Microsoft to release WinFS, LINQ, or DLINQ in order to takeadvantage of O/R Mapping LLBLGen Pro is already available and has proved to be a mature and stable product
Trang 17N-Tier Application Design
Programmers who create any kind of large programming project know the importance of keeping code organized Tier application design helps you separate your code into logical layers Generally, you would have a data-accesslayer, a business logic layer, and a user interface layer; some developers use more layers and some use less Hereare the details about what each layer would contain in this three layer design:
N-Data access layer: This section contains all the code necessary to execute SELECT, INSERT, UPDATE and
DELETE statements in the database, access views, run stored procedures, and convert between database data typesand the data types of your programming language
Business logic layer: This section would contain code that implements the rules of your business This is aboveand beyond simple database access For instance, code in this layer might validate the various parts of an order beforethe order is saved into a database or define the process for handling an order once it is saved into the database
User interface layer: This layer contains code that puts data into specific controls in order to display it for yourusers Hopefully, it contains only what is user-interface specific In the NET world, web application controls aredifferent from windows application controls, so this code cannot necessarily be re-used between different kinds ofapplications
The advantages of the three-tier design are the following:
• Using a three tier method, you would be able to change your application to a completely different user
interface without losing the other two layers of your code
• Business rules are saved in a central location If you decide to change the process for validating an order, youonly have to change it in one place
• If you change your database (from SQL Server to Oracle, for example), you would theoretically be able to
change only the data access layer and not the rest of your application Unfortunately, in most of the situationsthis is not a practical reality, as database-specific code has a way of creeping up to the user interface layer.While these methods are acknowledged best practices, most developers find that they do not have the time to designthe application this way; rules are violated frequently out of the need to just get the product out the door However,LLBLGen Pro helps accomplish the ideal design in the following ways:
• LLBLGen Pro will completely auto-generate the data access layer You do not need to do any hand-coding inthis layer
• LLBLGen Pro will optionally generate a business logic layer shell for you to get started with your businesslayer You do not have to understand the intricacies of inheritance and making custom classes to take
advantage of business logic classes; in LLBLGen Pro these classes are intuitively organized, powerful, andinfinitely extendable
• LLBLGen Pro collections and entity objects are bindable, making them extremely easy to add to NET
controls This can reduce the size of your UI layer
• Changing the database application and the data access layer without affecting the business logic and UI layers
is actually possible with LLBLGen Pro If you migrated your database schema and stored procedures to a newdatabase application, refrained from using any database-specific features (there are not that many) and your
schema matched exactly, you could actually re-generate your LLBLGen Pro data access layer and not make
any other changes to your application!
Stored Procedures, Inline, and Dynamic SQL
To help you understand how LLBLGen Pro works, let's take a look at how database information is integrated into a.NET application There are several different methods you can use to access data in your SQL Server database fromyour code These methods are inline SQL, stored procedures, and dynamic SQL
11
Trang 18Inline SQL: This is the most common method of database access seen in most tutorials, but it is by far the worst
method Inline SQL is illustrated in Example 1.13
SqlConnection conn = new SqlConnection(connection);
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = new
SqlCommand(“SELECT * FROM Orders WHERE OrderID=” + tbInput.Text, conn);
adapter.Fill(dataset);
return dataset;
Example 1.13 Inline SQL example
From a security standpoint, a user could enter any kind of data into an input field and have it concatenated directlyinto the SQL statement This presents an alarming security risk You do not want users executing arbitrary code inyour database Hackers who are familiar with SQL injection attacks6 can alter the above query to do about anythingthey want it to do
Also, from a maintainability standpoint, if you decide to change the name of the Orders table to Order, you do not
have any way to propagate this change to your data layer While the code will always compile correctly, it will throw
an exception when the query executes and the Orders table is not found
Stored procedures: Most security experts recommend using stored procedures exclusively for database access.From a security perspective, stored procedures are immune to SQL injection attacks, since parameters entered into astored procedure cannot change the query itself
From a maintainability standpoint, you do not have SQL strings inside of your code when you use stored
procedures, but you will still have stored procedure names in your code If you decide to rename a stored procedure,just like in the above example, you will not automatically propagate the stored procedure name change to your code.The code will compile correctly, but will throw an exception when it is executed and the stored procedure is notfound
The stored procedure method is also a management challenge due to the difficulty of maintaining a vast library ofstored procedures The previous version of LLBLGen Pro relied on auto-generated stored procedures to carry out theSELECT, INSERT, UPDATE, and DELETE operations For each table, there were 5 stored procedures generated (oneextra for selecting all the records) In essence the auto-generated stored procedures and custom stored procedurescreate another layer of code that must be maintained Maintaining code in SQL server can be much more difficultthan in Visual Studio for several reasons: the lack of IntelliSense, a difficult debugging environment, cryptic (andunhelpful) error messages, and the inability to organize similar functions into logical objects
Yet another disadvantage of stored procedures is that most C# code that calls a stored procedure returns an
un-typed DataSet or DataTable This again creates the problem of not knowing 100% of the time what kind of object will
be inside each column and row Although the code will compile, when executed it may throw exceptions if differenttypes of data are in different places
From a permissions standpoint, stored procedures do offer tighter security You can allow users access to only thestored procedures, and they would not be able to access the underlying tables to do any other kinds of changes (i.e.,change the structure of the table) Setting permissions with dynamic SQL (discussed in the next section) is a littlemore complex because you need to set SELECT, INSERT, UPDATE, and DELETE permissions individually on thetables themselves
Another commonly cited advantage of stored procedures over other SQL statements is performance The
architecture of SQL Server is believed to speed up stored procedures by precompiling the query when it is created.However, MSDN documentation7 states the following:
SQL Server 2000 and SQL Server version 7.0 incorporate a number of changes to statement processing that extend many of the performance benefits of stored procedures to all SQL statements SQL Server 2000 and SQL Server 7.0 do not save a partially compiled plan for stored procedures when they are created A stored procedure is compiled at execution time, like
6) For more information about SQL injection, see http://msdn.microsoft.com/msdnmag/issues/04/09/SQLInjection/ or query Google for “SQL injection attacks”
7) See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/architec/8_ar_da_0nxv.asp or query Google for “SQL Server” and
“statement processing”.
12
Trang 19execution plan reuse to all SQL statements.
The newer versions of SQL Server blur the lines between stored procedures and other SQL statements from a
performance standpoint The same query will be cached regardless of whether it is a stored procedure or a SQL
statement SQL statements also have the advantage of varyingwhereas the logic of a stored procedure is fixed While changing thestructure of the query means that a dynamic query will not takeadvantage of the caching feature the first time it is executed (butwill on subsequent executions), the dynamic query has thecapability of altering to fit the exact need The SQL statementtherefore could give the developer an opportunity to solve aproblem more efficiently than an existing stored procedure might.Keep in mind, though, that neither method is better than the other
all of the time; both techniques have strengths and weaknesses The main point here is that stored procedures do not always have a strong performance advantage over SQL statements
The last disadvantage of stored procedures is that complex procedures can get very ugly very quickly The ability
to do a complex search with many different optional parameters, optional joins, and a variety of sorting methodswould be exceptionally difficult with just one stored procedure
Dynamic SQL: The least common and probably least understood method of database access is Dynamic SQL With
this method, a custom component automatically generates the proper SQL statements for you as you use the object.Many developers do not even know this option exists, and understandably so If you do not have time to codeaccording to the best practices, you certainly will not have time to write your own component that generates SQLstatements automatically The good news is that you do not have to The developers of LLBLGen Pro have made thecomponents for you, and their components are smart enough to speak to a number of different databases You canthink of them as universal translators for databases This frees you up to interface with the components in a generic,non-database-specific manner
If you follow the development of Internet applications, the transition to dynamic SQL will seem quite natural Just
as HTML and JavaScript code in many of today’s web applications is not always written by hand, but instead
encapsulated into ASP.NET server controls which generate the correct code automatically, so new objects are
generating SQL to speak to databases, freeing the developer from having to write all this extra code manually
As the queries are generated, instead of concatenating SQL statements together, these queries become
parameterized, just like stored procedures This process also makes these statements immune to SQL injection
attacks Thus, with dynamic SQL, developers can get the security advantages of stored procedures without the hassle
of maintaining another layer of code in your database
In addition, to help with maintaining your code, LLBLGen Pro generates the equivalent of a master index to all theobjects in your database and all of their fields, saving you from having to hard-code strings in your code with tablenames, stored procedure names, and field names These enumerators and other LLBLGen Pro objects allow you to
consume data in a way that will not compile when the schema changes and you have refreshed the data access layer;
therefore LLBLGen Pro helps prevent schema changes from causing unanticipated exceptions in your code when it isexecuted
Complex querying is also much easier with dynamic SQL than stored procedures A dynamic query can grow toinclude joins where necessary or can alternatively use a variety of branching logic, optional parameters, and anypossible sorting option in the same method You have near-infinite flexibility with dynamic SQL, limited only by yourown ingenuity and creativity
For database access, dynamic SQL is powerful, under-used and often misunderstood as a method of talking toyour database By the end of this book, you will be an expert user of this type of access and you will enjoy all of theadvantages of this method over less efficient inline SQL and stored procedures methods
Stored procedures do not
always have a strong
performance advantage
over SQL statements.
13
Trang 20Data Type Conversion
Another problem that arises when talking to databases involves the conversion of database values into their NET
counterparts In the database world, a column of type integer can contain a whole number (like 5) or be null (if the
schema allows) In previous versions of the NET framework an integer would throw an exception if its value was null(or unassigned) When you read values from a database, you would have to account for the possibility of a null value
in your class library This accounting could take a lot of extra code to handle the type conversions and creates moreopportunities for mistakes In version 2.0 of the NET framework, Microsoft addresses this difficulty with the addition
of nullable types8 These types make it much easier to handle null values in NET than previous versions
LLBLGen Pro has used its own solution to the nullable dilemma from the beginning of the NET framework inorder to shield the developer from having to manage this complexity In LLBLGen Pro, the SQL data is automaticallyconverted to NET objects in the Data Access Layer with default values A null integer would become a NET integerwith a value of 0 For many situations, the minute difference between null and zero is unimportant However, forthose occasions when you actually care about whether the original value was zero or null, you can call a specificfunction that will tell you this value With LLBLGen Pro, if you need to assess nulls, you can handle them, but nullswill not keep you from getting your project done
Visual Studio Advantages
With every version of Visual Studio, Microsoft adds new features that often become essential for developers Here aresome of the best features from previous versions and the 2005 version:
• IntelliSense: Once you use IntelliSense you will never want to go back! If you have never used it, think of it
as automatic spell checking, grammar checking and word completion With IntelliSense, you simply writebetter code, in less time, and with fewer mistakes
• Debugging: Visual Studio has some of the best debugging tools around to help you figure out what is goingwrong with your code and to see what is happening step-by-step
• Design-time binding to your custom objects: You will probably want to use the the built-in binding
support to set up your controls visually With the advantage of a DataGridView you can add columns based
on the properties of the objects the control will contain before you even have to write a line of code
• New! One-click Deployment: Now, you can deploy your application to a file share or FTP site inside VisualStudio When the application is run, if there is a newer version available, your users will be prompted toinstall the update One-click deployment gives windows applications almost as much ease of deployment asweb applications!
Summary
For summary, here are the reasons the combination of LLBLGen Pro, SQL Server 2005, Visual Studio 2005, and theassociated techniques is so powerful:
• N-Tier design: Using N-Tier design is an effective way to break your code into layers that accomplish
different tasks and is easily reusable
• Customizable business layer templates: LLBLGen Pro generates templates for you to customize with youown code, so you do not have to create your own files, classes, or namespaces; you can start customizingimmediately LLBLGen Pro also generates classes to add your own custom validation logic as well
• Reusable core code: If you decide to switch to a web application, you can use the same generated classes andbusiness logic All you need to do is change the UI-specific code This book will show you how to develop sothat the maximum amount of your custom code is reusable
8) For more information about using nullable types in C#, see http://msdn.microsoft.com/vcsharp/2005/overview/language/nullabletypes/
14
Trang 21• Consistent and bug-free code: If twelve different programmers make your data-access code, they are
probably not going to be 100% consistent with naming conventions and structure, not to mention humansare guaranteed to make mistakes Generated code is 100% consistent and reliable
• Strongly-typed code that allows fewer errors: Almost all the code generated for you is strongly-typed,
which means that errors are discovered when the code is compiled—before it is run
• Lightweight and powerful code: While it is possible to generate strongly-typed DataSet objects in Visual Studio, LLBLGen Pro code is smaller, cleaner, and infinitely more powerful Like DataSet objects, all generated
Entity and EntityCollection objects are bindable And with new features in Visual Studio NET 2005, you do
more binding visually.
• Easier and less error-prone schema changes: Schema changes are a hassle because it takes time to figure outhow the changes will affect existing code and logic, both inside and outside the database With the O/RMapper, changes to the schema are updated into the generated code, and you immediately see where
breaking changes have occurred
• Database independent code: LLBLGen Pro abstracts your database from your application, so you are notlocked into one database application This flexibility means that you could switch to a completely differentdatabase with minimal to no impact on your custom code If you stick to functionality common to all
databases, you will not need to change a thing
• Visual workspace: Much of the work in Visual Studio can be done visually, without having to code by hand.The visual nature of these tools saves you time and frustration, and the results are much more predictable.Visual Studio NET 2005 adds even more visual features, and we will show you how to take advantage of thisnew functionality
• Powerful pre-built controls: With every new version of Visual Studio, the controls get better and better As
you learn how to use Visual Studio 2005’s bindable objects and DataGridView controls, you will be able to
present your data more professionally and efficiently
• Easy deployment: The newest version of Visual Studio has useful deployment options that make a Windowsapplication as easy to deliver to clients as a web application Client machines check for new versions of thesoftware automatically, greatly reducing the burden on the developer
In the next chapter, we will take a look at what an O/R Mapper is and how you use it to generate your data accesslayer and business layer
15
Trang 23The O/R Mapper
2
The O/R Mapper
“Sharpening the ax will not delay the work of cutting the wood.”
Chinese proverb
Chapter Goals
• Prepare the database
• Get acquainted with LLBLGen Pro object types
• Create a new LLBLGen Pro project and scan your schema
• Add database objects and configure them
• Discuss code generation options
• Generate your data access layer and business logic layer
As mentioned earlier, it is beyond the scope of this book to help you in designing a schema from scratch But there arethings that you can change in your schema to make sure you get the maximum possible benefit from the O/R Mapperand spend the least amount of time writing custom code, which we will cover in the next section
Preparing the database
Here are the tasks you need to perform on your schema before you begin development on your application:
Clean up your database Delete unused stored procedures, views, and tables You do not have to add these items
to your generated framework, but having to scroll through an unnecessarily long list is not a good use of your time.Tidy up your database beforehand for maximum efficiency
Give your tables non-prefixed, singular names based on their real-world counterparts: Do not use names like
“LD5_223” or “TBL_Orders” Name the table with order data Order, not Orders, as you want to be using an
OrderEntity, not an OrdersEntity Your code will be much more readable if your tables are named well.
Put Primary Keys on all your tables: An O/R Mapper cannot find the row if it does not know its uniquelyidentifying information Even if it is just an auto-numbering ID field, go ahead and give your tables primary keys.Remember not to overlook fields that are unique and might serve as a natural primary key, as you want to preventduplicate data wherever possible with good schema design
Define all your relationships in advance: An O/R Mapper can detect the relationships between tables and let you
traverse these relationships quickly and easily, but only if you define the relationships in your database For maximum
effectiveness make sure that all of your table relationships are defined before using the O/R Mapper If your schema isalready set and you cannot change it, you can tell LLBLGen Pro about the relationship even though it does not exist inthe database However, if at all possible, it is highly recommended to define all relationships in your database ahead oftime
Normalize to your heart’s content: Most of the time when you design a schema, you have to balance
normalization and usability If you split everything off in separate tables to keep from repeating data, nobody is going
to want to use your database because they will not be able to find any of the information! You do not want users tohave to pull five tables together just to figure out a customer’s email address! However, when you use an O/R Mapper,
it does not matter whether you have 5 tables or 50, they are all generated into their own objects, and, most
importantly, they are connected together with relationships Instead of having a meaningless integer when you read acolumn that contains a foreign key, you can move across to the row in that table to look up the name without any
17
Trang 24extra hassle If you tend to be conservative with your schema, consider doing more normalization than you mightordinarily do
Remember that nothing can fix bad database design: Instead of assigning auto-numbering ID fields to everytable, think through the data that the table will contain and use primary keys that will ensure you do not end up withduplicate data A little foresight will save you from having to spend days cleaning up data due to poor schema design
Our schema AdventureWorks
Once you have finalized your schema, you are ready to use LLBLGen Pro to create your data access and business
logic layers For the purposes of this book, we will be using the AdventureWorks example database included with SQL Server 2005 Microsoft finally replaced the Northwind database with an example that is more up-to-date and has much
better schema design! We will only be working with a few of the tables from this database—not the entire database.Figure 2.1 is a diagram of the tables we will be using in our example application
LLBLGen Pro Objects
Before we use LLBLGen Pro, let’s take a look at what this tool will provide us Here are the classes we will be gettingautomatically as we scan our schema and generate our code
Entities: For every table you add to your project, LLBLGen Pro will generate a specific entity class to represent thattable Each instantiated entity corresponds to one row in a specific table in your database For example, in the
AdventureWorks schema, LLBLGen Pro would create an object type called EmployeeEntity One EmployeeEntity object
18
Figure 2.1 AdventureWorks schema
SpecialOfferProduct
PK,FK2,I2 SpecialOfferID PK,FK1,U1,I2 ProductID I1 rowguid
Individual
PK,FK2,I1 CustomerID FK1 ContactID
EmailPromotion
Phone
PasswordHash PasswordSalt
U2 AdditionalContactInfo
I1 rowguid ModifiedDate
Employee
PK,I4 EmployeeID I2 NationalIDNumber FK2 ContactID I1 LoginID FK1,U1 ManagerID Title BirthDate MaritalStatus Gender HireDate SalariedFlag VacationHours SickLeaveHours CurrentFlag I3 rowguid ModifiedDate
SalesOrderDetail
PK,FK1,I2 SalesOrderID PK,I2 SalesOrderDetailID
CarrierTrackingNumber
OrderQty FK2,U1 ProductID FK2 SpecialOfferID UnitPrice UnitPriceDiscount LineTotal I1 rowguid ModifiedDate
MaxQty
I1 rowguid ModifiedDate
PK,I3 SalesOrderID RevisionNumber OrderDate DueDate
ShipDate
Status OnlineOrderFlag I2 SalesOrderNumber
PurchaseOrderNumber AccountNumber
FK7,U1 CustomerID FK3 ContactID
FK8,U2 SalesPersonID FK9 TerritoryID
FK1 BillToAddressID FK2 ShipToAddressID FK4 ShipMethodID
FK5 CreditCardID CreditCardApprovalCode FK6 CurrencyRateID
SubTotal TaxAmt Freight TotalDue
Comment
I1 rowguid ModifiedDate
PK,I3 CustomerID
FK1,U1 TerritoryID
I1 AccountNumber CustomerType I2 rowguid ModifiedDate
Address
PK,I3 AddressID I2 AddressLine 1
I2 AddressLine 2
I2 City FK1,U1,I2 StateProvinceID I2 PostalCode I1 rowguid ModifiedDate EmployeeAddress
PK,FK1,I2 EmployeeID PK,FK2,I2 AddressID I1 rowguid ModifiedDate
PK,FK3,I2 CustomerID PK,FK1,I2 AddressID FK2 AddressTypeID I1 rowguid ModifiedDate
Trang 25The O/R Mapper
would represent one row in the Employee table We can create a new row, retrieve an existing row, update a row, or delete it by interacting with this EmployeeEntity object Each column in the Employee row is exposed as a property of the EmployeeEntity object LLBLGen Pro refers to these properties as fields
Collections: For every entity class, LLBLGen Pro also creates an entity collection An entity collection contains entity objects, just like a table contains rows From the Employee table in the AdventureWorks database, LLBLGen would create an EmployeeCollection that holds EmployeeEntity objects These collection classes eliminate the need for
DataTable objects and are both strongly-typed and bindable Instead of running a stored procedure and getting a DataTable, you can create criteria using the LLBLGen Pro framework and retrieve a collection of entities that match
your criteria
Entity relationships: Built into each entity are all relationships in the database involving that table These
relationships help you navigate between related tables Using an EmployeeEntity, you can immediately retrieve the related ContactEntity (using the 1:n relationship between the Employee table and the Contact table) or a
AddressCollection (using the m:n relationship through the EmployeeAddress table) You will either get a single entity or
an entity collection depending on the type of relationship This built-in property saves you the trouble of navigating
to that table and filtering out the unnecessary rows yourself
Typed views: Views in the database can be wrapped as strongly-typed DataTable objects This means that
LLBLGen Pro will create a new class that inherits from a NET DataTable that will specifically define the contents of
every column in that view Typed views are read-only A new feature in the latest version of LLBLGen Pro also allowsyou to add a view from the database as an entity as well as a typed view We will discuss the differences between thesetwo methods in later chapters
Typed lists: Typed lists are the only objects created by LLBLGen Pro that do not correspond one-to-one withdatabase objects When you generate your code, you have the option of creating your own strongly-typed lists of
columns from either one table or multiple tables We could, for example, create a list from the Employee and Contact tables, but only use the columns BirthDate, FirstName, and LastName We could add the criteria “Gender = F”, and fill
our typed list with only these rows Typed lists are handy when you need very specific information that does notnecessarily correspond to a single table/entity or you only want to grab a subset of information for a given set oftables Like typed views, typed lists are read-only
Stored procedure caller classes: Stored procedures that you select will be wrapped in a layer of code, makingthem easy to access This can make the migration to LLBLGen Pro much easier, as you can gradually wean yourself offunnecessary stored procedures without having to migrate all at once While the parameters of the stored procedure
are strongly-typed, remember that the result set is still an untyped DataSet Despite this disadvantage, if you only used
LLBLGen Pro to expose your stored procedures in your data access layer with a consistent naming scheme, it wouldstill save you hours of development time
Now that we have a good idea of what items we can have generated with LLBLGen Pro, let’s look at the schemascanning and code generating process
Scanning the Schema
Scanning your database schema is relatively straightforward The designers of LLBLGen Pro helped make this process
a point-and-click affair
Simply open LLBLGen Pro and go to File > New Project
(Figure 2.2) Fill in the name of the project (“AW.Data”), your name, and a location to store the file We
recommend saving the file in My Documents\Visual Studio 2005\Projects\AW.Data since this location is also where
you will be generating your code
Select SQL Server 7/2000/2005 Driver (SqlClient) as the database driver.
Enter the name of your SQL Server and click Connect.
Select the AdventureWorks Database.
Leave the checkboxes under the “Elements to read from the database schemas” heading as they are, with Tables,
View, and Stored Procedures selected.
Click Create to start the process of reading your database’s schema.
19
Trang 26During this process, the application is reading your schema and saving the information into your project file Onceyou have finished this scan, you do not have to be connected to your database in order to complete the code
generation process The only time you will need to connect to the database again is if you make schema changes andneed to regenerate your code Working in this disconnected manner is both convenient and expedient
Once the scanning process has completed, you should see a screen like the one in Figure 2.3 From here we willadd objects from the database and configure them
20
Figure 2.3 LLBLGen Pro main project screen
Figure 2.2 New LLBLGen Pro project options
Trang 27The O/R Mapper
Creating Entities
The first set of items we need to add to our project are entities We now need to tell LLBLGen Pro exactly which tablesfrom our database we would like to use
(Figure 2.4) Right-click on Entities in the left bar, and select Add New Entities Mapped on Tables from Catalogs(s).
The Designer lets you select from a list of all the tables in your database At this step, you will generally want to add
all the tables you think you might ever access Only leave a table out if you have a specific reason not to include it or
you know for certain you will never use it When you select tables, LLBLGen Pro will examine all the relationshipsbetween the tables and create methods to navigate between the entities The more tables you add, the more
relationships LLBLGen Pro will find—including relationships you had not anticipated!
For this walk-through, select only the tables listed in Table 2.5 Adding tables is as simple as checking the boxes (Figure 2.6) and clicking Add to project when you are done You will see the tables we just added under the
Entities node (Figure 2.7).
Table 2.5 List of tables to add as entities from the AdventureWorks database
Figure 2.4 Adding entities to the project
Trang 28Entity Options
Now let’s take a look at all of the options that you can configure for every entity in your project
22
Figure 2.6 Table selection screen
Figure 2.7 Newly added entities
Trang 29The O/R Mapper
Right-click on the Address entity and select Edit/Properties.
From the entity edit screen (Figure 2.8) you will be able to set specific names for each property and relationship.Because each column in the table becomes an entity property with the same name, as long as you named your
database fields well, you should not need to change anything here This list will also tell you the database type of eachcolumn and the corresponding NET type that the column will become in your class LLBLGen Pro also detectswhether or not the column is read-only, the length of the field, and whether or not it can be null Through this cross-checking process, the data layer can catch some errors even before the data is saved in the database
Select the Fields on relations tab.
(Figure 2.9) This screen shows a list of all the detected relationships for this entity and the name of the property thatyou use to access the related entity or entity collection For each relationship, you will see the name of the relationship(field name), the two tables that the relationship exists between, and the type of relationship (1:1, 1:n, m:1, m:n) For
this entity there are 14 different relationships! The name given to this field name/property is based on the name of the table on the other side of the relationship For the first relationship in the list, the name is StateProvince
Notice that the 4th relationship in this list, ContactCollectionViaSalesOrderHeader, is a many-to-many relationship that we probably would not have created on our own It traverses the SalesOrderHeader table and allows us to retrieve
a collection of Contacts directly from an Address These extra relationships are helpful additions that do not cost you
any extra time, but that might come in handy later when you are trying to solve a specific problem
Select the Relations tab.
The Relations tab allows us to look specifically at the relationship objects themselves (Figure 2.10) Having our
relationships already defined in our database certainly makes our job easier since we do not have to define themmanually
23
Figure 2.8 Entity edit screen
Trang 30This tab will be important if you want to use a particular relationship that does not exist in your database's schema;
you can manually add new relationships here by clicking Add new custom 1:1/1:n/m:1 relation or Add new custom m:n
relation.
24
Figure 2.9 Entity relationships mapped as fields setup screen
Figure 2.10 Entity relationships setup screen
Trang 31The O/R Mapper
Select the Fields on related fields tab
This tab allows you to have a field from a related entity visible as if it were part of this entity For example, in the
Address table, we have a foreign key that points to a row in the StateProvince table Normally, if we want to know the
name of the state or province we have to look it up However, if we map the name of state or province as a field in our
Address entity, we will have easy access to the value without traversing a relationship to another entity (Note: When using fields mapped to related fields it is important to use Prefetching, which is discussed in Chapter 10).
Add the following fields on related fields to the Address entity from the StateProvince table by clicking on Add
new, and selecting the correct field from the Mapped on field list: StateProvinceCode, Name, and CountryRegionCode
(Figure 2.11)
Also, make the following changes to the employee entity:
From the main project screen, right-click on the Employee entity, and select Edit/Properties.
Select the Fields on relations tab.
Change the Employee field name to “Manager”.
Change the Employee_ field name to “Manages”.
25
Figure 2.11 Fields on related fields edit screen
Trang 32Adding Views
Now, we will choose the views in our database to add to our project For now, we will be working with one viewprimarily As we mentioned earlier, with LLBLGen Pro, you can consume a view in two ways First, you can add aview as a typed view
From the main project screen, right-click on Typed Views and select Add New Typed Views from Catalog.
We are presented with a list of all the views in our AdventureWorks database (Figure 2.12)
Select vIndividualCustomer and click Add to project.
Right-click on the vIndividualCustomer that was just added and select Edit/Properties.
(Figure 2.13) The only items you will customize with a typed view are the name of typed view and the field names Ifthese items were poorly named in the database, correct them here
Change the name of the view to CustomerView.
The other way of using a typed view is to add it as an entity By adding it as an entity, you will end up with a
collection instead of a typed DataTable You also have the capability of adding relationships to other entities, which
will make filtering rows easier Let’s add the same view as an entity as well
Right-click on Entities and select Add New Entities Mapped on Views From Catalog(s) (Figure 2.14).
Select the vIndividualCustomer view and select Add to project.
Right-click on the new vIndividualCustomer entity and select Edit/Properties.
Change the name of the entity to CustomerViewRelated.
26
Figure 2.12 Typed view selection screen
Trang 33The O/R Mapper
On the Entity Fields tab, select the CustomerID row, and check the boxes for Is Readonly and Is part of the primary
key (Figure 2.15).
On the Relations tab, click the Add new custom 1:1/1:n/m:1 relation (Figure 2.l6).
Select Primary key side, and select SalesOrderHeader as the related table.
Make sure both the Primary Key field name and the Foreign Key field name are displaying CustomerID.
Adding the relation will make it possible to retrieve a row in this view directly from an order in the SalesOrderHeader
table
27
Figure 2.14 Adding a view as an entity
Figure 2.13 Typed view field names edit screen
Trang 34Creating Typed Lists
Now we will create a typed list
From the main project screen, right-click on Typed Lists and select New Typed List.
Enter the name “CustomerList” and click OK.
28
Figure 2.15 Entity field configuration screen for view mapped as an entity
Figure 2.16 Adding a relationship to a view mapped as an entity
Trang 35The O/R Mapper
(Figure 2.17) You are presented with a list of all the entities in your project From the list of entities, you can chooseone or more entities to add to your typed list You will then edit the entire list of columns from all the tables you haveselected in order to include only the columns that you want to appear in your typed list
Select the Customer entity, and click the Add>> button
29
Figure 2.17 Typed list configuration screen
Table.Field Name Field Alias
Trang 36You can only add entities to the list that are related Now that you have chosen one entity, the other unrelated entities
in will be grayed-out These tables will define the source from which we will select the columns we want
In the order that they are listed, add the following tables: Individual, Contact, CustomerAddress, Address Type,
Address, StateProvince, CountryRegion.
Now we can select the specific columns that we are interested in We will be choosing columns in such a way that the
result will be similiar to the columns in the vIndividualCustomer view.
Click on the Fields mapped on entity fields tab, and select the columns according to Table 2.18, making name
changes where indicated As you check the box next to the list of available field names, they are added to thecollection at the bottom of the form (Figure 2.19) These name changes are necessary since there are multiplefields with the column name “name”, and each field name in the typed list must be unique
That is all there is to creating a typed list Our effort will produce a strongly-typed DataTable with these 16 columns.
We can create any criteria that we like when we use this list, but the rows that are returned will always contain these
16 columns Because we know the exact schema of the result set, a typed list gives us an advantage over a storedprocedure No surprises at run-time!
Adding Stored Procedures
Now we will add a stored procedure to the project
From the main project screen, right-click on Retrieval Stored Procedure Calls and select Add Stored Procedure Calls
Select UsbGetEmployeeManagers and UsbGetManagerEmployees and click Add to Project.
Right-click on UsbGetEmployeeManagers and select Edit/Properties
(Figure 2.20) In the edit screen of a stored procedure, you can change the stored procedure’s name or the names ofthe parameters Again, if these names were poorly labeled in the database, take time to correct them here Note thatchanging parameter names here only changes how the stored procedure is referenced in your generated code
Changing the name in your LLBLGen Pro project does not actually change the stored procedure’s name in yourdatabase
30
Figure 2.19 Typed list field selection screen
Trang 37The O/R Mapper
We have finished adding database objects to our LLBLGen Pro project and now we are ready to generate our code.Before doing so, let’s look at the different code generation options available
Self Servicing vs Adapter
LLBLGen Pro offers two different template groups to select when generating code: Self-Servicing and Adapter In theSelf-Servicing template group, entity objects are responsible for their own persistence (saving their own changes tothe database) The entity class itself contains logic to know which fields were updated and where to find the database,
table, and row necessary to persist itself All you need to do is call the Save() method As you navigate the
relationships of the objects, the data is retrieved from the database as it as needed, without your explicit direction.This is referred to as lazy loading Lazy loading is useful because it abstracts the specific database call from the upperlayers of code However, when it is used incorrectly data access can execute in a grossly inefficient manner (manysmall queries to your database instead of one large query) If you pay attention to how the data is being retrieved asyou use the object you can use a process called prefetching to consolidate database queries and increase performance.Prefetching is discussed in Chapter 10
Using the Self-Servicing template group is similar to an office environment where coworkers are empowered andexpected to know what needs to be done to do their individual jobs You do not need to tell them the all the details.Just point them in the right direction, and they will work out the details on their own
The Self-Servicing template is strongly entity-focused You can see what using the self-servicing code is like whenfetching an order in Example 2.21
Example 2.21 Self-servicing code example
In the above example, as soon as the entity in instantiated in Line 1, all the data is fetched from the database andloaded into the object In Line 2, we can immediately begin using or updating the entity’s properties To save the
changes back to the database, we simple call the Save() method in Line 3
The Adapter template group uses an object called a DataAccessAdapter to interact with the database Instead of
database queries happening behind the scenes automatically, every database transaction will be explicitly called
through the DataAccessAdapter object In this way, the DataAccessAdapter is similar to the built-in TableAdapter object
in NET With this adapter, you have more control over the database connection and can choose when to open it,how long it remains open, and when to close it
31
Figure 2.20 Stored procedure parameter list
Trang 38The Adapter template group is more like a classroom, where the teacher is firmly in control and tells the studentsexactly what to do Students are not empowered to simply “take care of themselves” The students follow the teacher'sspecific instructions.
The Adapter template group has the advantage of fine-grained control over every database query In addition, italso supports multiple database types and multiple databases If your data needs are complex, the Adapter templategroup might be your only option The Adapter template organizes code around an object that provides data servicesand is independent of the entity objects themselves In Example 2.22, we use an Adapter code to fetch an order
DataAccessAdapter Adapter = new DataAccessAdapter();
ContactEntity MyContact = new ContactEntity(34);
Adapter.FetchEntity(MyContact);
MyContact.FirstName = tbFirstName.Text;
Adapter.Save(MyContact);
Example 2.22 Adapter code example
With Adapter code, we can instantiate the Entity in Line 2, but until we call the FetchEntity() method in Line 3, the data will not be loaded into the object from the database We must use the DataAccessAdapter to read and update the
• Bundles persistence inside entity objects
• Allows data to load itself automatically as it is needed without explicit commands
• Does not require extra objects to perform data access
• Only works for a single database type and a single catalog
• Can be used easily and intuitively
Adapter
• Exposes persistence as a service
• Allows finer database control Each database query is explicit
• Can target multiple databases and catalogs
• Requires an extra object and a few more lines of code
One Class vs Two Classes
(Self-Servicing only)
If you use the Self-Servicing template, another decision you will need to make is whether to use a one-class scenario
or two class scenario In a general scenario (one class), only one set of entity classes are created If you need toextend the generated framework, you can place your custom code inside of the generated classes between specialmarkers to ensure that it will not be overwritten if the code is regenerated Outside of using special markers, youronly other option would be simply to create your own set of custom classes that use the generated framework You
might create an AddressManager class that consumes all the entities associated with placing an order (Figure 2.23)
A better option in certain situations is to use a two-class scenario In this case, two sets of entity classes arecreated The first type is known as the base type and is exactly the same as the entity class in the one-class scenario,but with a different name The extra entity class is an empty class that inherits from the base class You can use thisshell as an instant business layer for all of your custom code This class is kept completely separate from the generatedcode and will never be overwritten when the code is regenerated, so you will not lose your changes Figure 2.24 is an
9) While template modification is outside the scope of this book, LLBLGen Pro customers can freely download the LLBLGen Pro Software Development Kit (SDK) from Solutions Design to get tools and instructions for creating templates and adding custom code to existing templates.
32
Trang 39The O/R Mapper
example of a two class scenario In this setup, you can place your business logic inside the AddressEntity object,
instead of writing your own “manager” classes Entity classes inherit all the functionality of the base classes, but arenever overwritten when the code is regenerated The two class scenario is highly recommended to fulfill the N-tier best practice in the least amount of time
33
Figure 2.23 General scenario (one class) diagram
Figure 2.24 Two Class scenario diagram
Trang 40Generating the Code
We are now ready to generate the code for our selected database objects
Click on the Project menu and select Generate.
The code generation screen with the 4 main options that you will set for your project is shown in Figure 2.25
In the Generator configuration to use option, select Self Servicing, two class scenario (Full) VS.NET 2005.
The Full option in the Two Class Scenario will generate what is necessary to start the project the first time It will
create both the base classes (data layer) and the inherited classes (business layer)
After generating the first time, you would select Servicing, two class scenario (Base Classes Only) for subsequent code
generation tasks Regenerating your code is covered in Chapter 12 Whenever you regenerate your code, it is alwaysadvised that you make a backup copy of your code or check it in to source control before you start, just in case youmake the wrong selection You will never lose your custom code if you make a backup beforehand
In the Template set to use option, select C# template set for SQLServer.
In the Root namespace option, enter “AW.DATA”.
The namespace decision is important: you cannot change this option without regenerating your code! Thenamespace is so heavily embedded in your classes, it would take you days to change it manually Choose a logicalnamespace that fits in well with your company’s namespace conventions
34
Figure 2.25 Generator configuration screen