Posted by K. Scott Allen on Oct 12, 2009 in
Dotnet |
View Original Article
Health monitoring has been available in ASP.NET since v 2.0, and the health monitoring features can give you information you can’t find anywhere else. I was troubleshooting an MVC application recently and needed information about the application:
- When was the application starting?
- When was the application shutting down?
- Why was the application shutting down?
- When was view compilation taking place?
This is the type of information you can record with health monitoring in both Web Forms and MVC applications.
You’ll typically want to record health data into SQL Server for analysis. The first step is to create the ASP.NET “application services” database. You might already be using the database if you are using ASP.NET features like the SQL membership provider for forums authentication. If not, the aspnet_regsql tool will create the tables and procedures required for health monitoring in any database you choose.
Once the database tables are in place, you just need a bit of configuration in web.config. The following configuration is telling the health monitoring system to send application lifecycle events to a SQL Server provider.
<system.web>
<connectionStrings>
<add name="appDB" connectionString="data source=..." />
</connectionStrings>
<system.web>
<healthMonitoring enabled="true">
<providers>
<add name="sqlProvider"
type="System.Web.Management.SqlWebEventProvider"
connectionStringName="appDB"
buffer="false"
bufferMode="Notification" />
</providers>
<rules>
<add name="lifeCycle"
provider="sqlProvider"
eventName="Application Lifetime Events" />
</rules>
</healthMonitoring>
The health monitoring system will start to populate the aspnet_WebEvent_Events table with detailed event information. There is no built-in feature to display the events, but you can always setup a simple display view, connect with Microsoft Excel, or connect with any SQL query tool. The information is fairly detailed.
What about ELMAH?
Many people are using ELMAH for error logging. ELMAH is easier to use and configure compared to the built-in health monitoring features. ELMAH also includes a number of display options, including the ability to generate RSS feeds from logged events, and sending log events to Twitter. Hanselman has a great post on using ELMAH in an MVC application. ELMAH’s creator is Atif Aziz, who has a number of other interesting projects listed on his web site: www.raboof.com.
If you are already using ELMAH, you still might consider looking at health monitoring for some scenarios. ELMAH is a fantastic error reporting tool, but some of the information available from health monitoring is only available via health monitoring, since it has a close tie to the ASP.NET runtime. If you want to take the health monitoring events and publish them via ELMAH, than Eric Schoenholzer (@bluesware) has written an ElmahEventProvider you can download from the Files section of the ELMAH project site.
Posted by W3Avenue Team on Oct 12, 2009 in
CSS,
Javascript |
View Original Article
CSScaffold is a CSS framework written in PHP. Unlike pure CSS framework (e.g., Blueprint, etc) that uses the standard abilities of CSS, it uses PHP to extend CSS. The syntax looks and feels exactly like CSS, except that you have additional features.

Scaffold requires a web server with PHP 5+; Mod_rewrite for Apache is required if you want it work automatically route your CSS files through Scaffold. If you don’t want it work automatically, you can point your CSS files directly to Scaffold.
Features
- Constants
- SASS style Mixins
- Nested Selectors
- Expressions
- Compressed, Cached and Gzipped on-the-fly
- Perform PHP operations
- Extendable through Plugins
Plugins
- Layout – Create 960.gs style grids with Mixins and classes.
- OOCSS – Extend one selector using another selector
- Browsers – Target specific browsers
- Minify – Uses the minify library to compress your CSS
- Icy Compressor – An alternative to Minify
- Validate – Validates your CSS using the W3C validator
- Image Replace – Image replace titles by just linking to the image. Scaffold will find the height and width of the image and take care of the rest of the properties needed to image replace the text.
Developed by Anthony Short; CSScaffold is available for download under New BSD License. You can find further information, demo & download on CSScaffold Project Website.
Similar Posts:
Tags: Anthony Short, CSS Framework, Libraries/Frameworks, New BSD License
Posted by Garth Braithwaite on Oct 12, 2009 in
Flex |
View Original Article
At MAX we were able to interview some amazing members of the RIA community. In this block of podcasts we reviews the day 2 keynote and speak with Alan Queen, Bob Flynn, Ed Sullivan, Mark Anders, and Stephen Hammond.
Tags: adobemax, Blogs, podcast, riaradio
Posted by Guest Posting on Oct 12, 2009 in
Design & Graphics |
View Original Article


by György Fekete
Comment forms are an essential part of our blogs, social networks and websites. Comment forms are our websites’ communication channel. Through these forms we get feedback on our content; therefore, it’s necessary to design them in such a way that they are easy to understand by our user base.
A good comment form should align with our website’s main design, but at the same time it should be interesting enough to encourage easy commenting. It must be usable and accessible if we want to capture all of our visitors’ feedback.
We searched for some examples and found original and creative ones. Below we present these examples along with a few guidelines that a designer should follow to make a great comment form.

Guidelines And Best Practices
Even a relatively simple-looking comment form can hide a very complex design behind it. There are many variables that a designer should take in consideration. The ones presented in this article are the most important and can be applied not just to comment forms but to Web forms in general.
1. Keep it simple
People don’t like filling in (yet more) comment forms, because there’s usually only one field that changes for them: the message text field. All of the other fields generally remain the same.
A good design should take this into consideration. When you design a comment form, make sure you don’t include text fields that are not necessary. For example asking users to write their country or phone number in a comment field is a mistake because it has no relevance to the form itself. The only purpose of a comment form is to get the user’s feedback and to communicate with the user.
The following comment form makes this mistake, although it does make it an optional text field.

Keeping the comment form simple enough reduces completion time, another essential attribute that a comment form should have.
Another good practice that contributes to reduced completion time is to top-align the form labels with their associated fields. This improves text scanning. Top-aligned labels should be used when a user is already familiar with the fields that need to be filled: for example, name, email address, etc.
A designer should use spacing and contrast when designing comment forms; these effects also improve text scanning. The following screenshot demonstrates this.

2. Give meaning to the form elements
A comment form stands in for the content author or website owner. Users are not robots; they’re human beings. When they post their comments, it’s like they are talking to the content author. People do not speak in keywords like “Comment” or “Feedback”; instead, they speak in gentler, more meaningful ways, like “Share your thoughts with us.” This is what a comment form should do: communicate its purpose in a meaningful way.
Instead of plain old titles such as “Comment here,” a designer should give meaningful, more natural-sounding titles like “Leave a comment” or “Add your opinion.”

Another example is when a user is asked to fill in his or her website address, but the label of the text field just says “URL.” There are users who are not familiar with this term, so a designer should also include a definition, the meaning of that expression.
3. Identify required fields
Not knowing which text fields are required and which are optional just increases confusion. A designer should clearly separate required fields from the rest by marking them.
Marking required fields with text (e.g. “required“) is good, but using the “*” character is often simpler and better because it’s widely used for this purpose and gives a visual representation of the text “required.”


4. Guide the user in filling the form
The primary goal of every comment form is successful completion by the user. Every comment form should have a solid design behind it that guides the user from start to finish. Every form has its own completion flow. Don’t break this flow.
Many users interact with comment forms by using the Tab key to switch from one text field to the next. A designer should implement proper HTML markup so that tabbing works as expected.
The form in the following screenshot breaks the completion flow. The mistake lies in the placement of the “Submit” button. It should be placed after the check box “Notify me of follow-up comments via e-mail.”

5. Minimize the pain
Every interaction with a comment form triggers complex actions in the user’s brain. Every text field can be considered a question that the author asks of the user. Knowing this, we should construct a comment form so that it “asks” easy, familiar “questions” first, such as “Name” and “Email address.”
It is a bad practice to place the message field first in the comment form, because this demands a more intense thought process of the user and it could result in the user not completing the form. Always place the more demanding fields at the end.

6. Validate on the fly and efficiently
Using AJAX to validate email addresses is essential and contributes to completion flow. If we were to use server-side validation, the page would have to refresh and the user wouldn’t get instant feedback about whether the fields were completed correctly.
Also keep in mind usability and AJAX’s obtrusive nature. A developer should emphasize unobtrusive, on-the-fly validation.
In some cases, it is not obvious at first that a text field requires validation, often resulting in poor usability. For example, it is a mistake to validate a “Name” text field to contain only alphabetical characters and nothing else, because then people with names such as “O’neil” are left out.
If a comment form’s text fields are constrained to a specified maximum character count, then the designer should indicate this next to the relevant field. Many comment forms use reverse counting, meaning they count down from the maximum allowed characters to let users know how many characters they have left to use.

7. Avoid CAPTCHAs if possible
CAPTCHA stands for “Completely Automated Public Turing test to tell Computers and Humans Apart.” The most widely used type of this is text embedded as an image to test verify whether a user is human or a spambot.
These kinds of tests should be avoided if possible. A more accessible solution is to use a third-party spam filter service, such as Akismet.
8. Don’t break habit
When designing your comment forms, always keep in mind the famous quote “Don’t try to reinvent the wheel.” There are many designs that have been tested and just work. Don’t try to come up with your own, because it will most likely fail.
You should align your design with traditional comment form designs, meaning you should include three, or at most four, fields, such as “Name,” “Email address,” “Website URL,” and “Message (Comment).”

9. Keep in mind localization
It is most likely that not only English-speaking users visit your website and comment on your content. Designers shouldn’t discriminate against these visitors; instead, they should keep in mind the peculiarities of different languages.
For example, in many European countries, names are written in reverse order, last name first and first name last. And many people, mostly in Arab cultures, have more than two names. If a designer includes only two fields, “First name” and “Last name,” then these people won’t be able to write their name completely.
A best practice is to simplify this type of text field and just include a “Name” field.

10. Do not use visual elements excessively
It’s true in many cases that an image is worth a thousand words, but it’s not a good motto to follow when designing comment forms.
A designer can use icons and other visual elements moderately but should keep in mind that different icon styles confuse visitors.
In the following screenshot, the icon in the third field does not entirely convey that the field should contain a website address; and not including a descriptive label next to each field can confuse users even more.

Comment Form Showcase
AisleOne.net

iso50.com

cssVault.com

daily.creattica.com

designsojourn.com

elitistsnob.com

hicksdesign.co.uk

ideas.veer.com

inspiredology.com

lucyblackmore.co.uk

typeneu.com

underconsideration.com

wilsonminer.com

About the author
György Fekete is a Web developer with five years of experience in Web design and development. He is the founder of Primal Skill Ltd., an established Romanian Web design and development studio. He also blogs about Web design, development, business and startups at blog.primalskill.com. (al)
Tags: Forms, How To's, usability, webdesign
Posted by Marc Edwards on Oct 12, 2009 in
Design & Graphics |
View Original Article

Most people who have designed websites or apps in Photoshop will, at one point or another, have had issues trying to match colors in images to colors generated by HTML, CSS or code. This article aims to solve those problems once and for all.
Color Management to Match Colors Across Multiple Devices
In the print world, color management typically involves calibrating your entire workflow, from scanner or digital camera to computer display to hard proofs to the final press output. This can be quite a tall order, especially when the devices use different color spaces — matching RGB and CMYK devices is notoriously hard.
When designing or editing for TV, calibrating the main editing display and using a broadcast monitor are common; these show real-time proof of how the image will look on a typical TV in a viewer’s home. In such a scenario, color management offers many benefits and is highly recommended.
When building Web and application interfaces, the situation is a little different. The final output is the same device that you’re using to create the artwork: a computer display (putting aside for now differences in gamma between Windows, Mac OS X prior to 10.6 and the iPhone, which we’ll cover later.)
There is a catch, though. Even though you’re creating the Web or app interface on the same device that the final product will be shown on, the colors will have various sources: images (typically PNG, GIF and JPEG), style markup (CSS) and code (JavaScript, HTML, Objective-C, etc). Getting them all to match can be tricky.
The Goal
When designing websites or app interfaces, we want to perfectly match the colors that are displayed on screen in Photoshop and that are saved in files with what’s displayed in other applications, including Firefox, Safari and the iPhone Simulator. Not only do we want the colors to look the same, but we want the actual values saved in the files to perfectly match the colors we have defined in Photoshop. Colors should not shift or appear to shift in any way, under any circumstance.

Why Is This So Difficult?
Photoshop applies its color management to images displayed within its windows and to the files it saves. This is a bad thing if you’re working exclusively with RGB images for Web or on-screen user interfaces. With the default Photoshop settings, #FF0000 will actually display as #FB0018, and #BB95FF will display as #BA98FD. The differences are subtle but definitely there.
How Does Photoshop Differ From OS X And Windows?
OS X’s color management is applied to the entire display at the very end of the processing chain, after the main buffer in video ram. This means that although color management is applied, the software utilities that measure color on screen (like /Utilities/DigitalColor Meter) will report the same values that you have saved in the file or entered as your code. I believe the color management in Windows Vista and Windows 7 (Windows Color System) works in a similar fashion.
Photoshop’s color management is applied only to the image portion of its windows and to the files it saves. This color correction happens as Photoshop draws the image on screen, so software utilities that measure color on screen often report different colors from the ones you have specified. It’s worth noting that OS X’s color management is applied on top of Photoshop’s.
The best solution I’ve found is to disable Photoshop’s color management for RGB documents as much as possible. Doing so forces the RGB colors that are on screen and saved to the file to match the actual color value. If you need to calibrate your monitor for Web and app design work, then you would best be served by changing it at the OS level.
Disabling color management used to be quite easy in Photoshop CS2 and all versions prior, but it now requires a little more skill.
Disabling Photoshop’s RGB Color Management
These instructions are for Photoshop CS4 on Mac and Windows. Setting up CS3 is very similar.
Step 1: Go to Edit → Color Settings and set the working space for RGB to Monitor RGB.

Step 2: Open a document and go to Edit → Assign Profile, then set it to Working RGB. This must be done for every single document you work on.

Step 3: Ensure View → Proof Colors is turned off.
Step 4: When saving files with Save for Web & Devices, ensure that Convert to sRGB is turned off. If you’re saving a JPEG file, then also turn off Embed Color Profile (you may want this turned on for certain photos, but chances are you’ll want it off for interface elements and icons).
Difference Between “Assign Profile” And “Convert To Profile”
Now would be a good time to mention the difference between Assign Profile and Convert to Profile, so that you know which to use when.
Each Photoshop document contains a color profile that’s separate from the actual color data stored for each pixel. Assign Profile simply changes the profile in the document, without affecting any of the color data. It’s a non-destructive action: you can assign a new color profile to your documents as often as you like without doing any damage. Assigning a new profile may change the way your document appears on screen, but the data contained in the file will remain unaltered.
Convert to Profile is quite different. Not only does it assign a color profile to the document, but it tries to keep your image looking the same on screen. It does this by processing the color data contained in the file for each pixel. Converting to a new profile will more likely preserve a document’s color on screen, but the data contained in the file will be permanently altered. Use with caution.
If you’re copying layers from one Photoshop document to another, you will want to ensure that the documents have been assigned the same color profile.
Illustrator Is The Same As Photoshop
If you would like images saved in Illustrator or imported from Illustrator to Photoshop to match as well, then follow the steps below. These instructions are for Illustrator CS4 on Mac and Windows. Setting up Illustrator CS3 is very similar.
Step 1: Go to Edit → Color Settings, and set the working space for RGB to Monitor RGB.

Step 2: Open the document and go to Edit → Assign Profile. Then set it to Working RGB. This must be done for every single document you work on.

Step 3: Ensure that View → Proof Colors is turned off.
Step 4: When saving files with Save for Web & Devices, ensure that Convert to sRGB is turned off. If you’re saving a JPEG file, then also turn off Embed Color Profile (again, you may want this turned on for certain photos, but chances are you’ll want it off for interface elements and icons).

Gamma Differences
Windows has used a gamma of 2.2 since its introduction. Mac OS X has used a gamma of 1.8 for all versions except Snow Leopard (the latest release), which uses 2.2. What does this mean? Prior to Snow Leopard, Web pages looked darker on Windows. Thankfully, both operating systems are now in sync, so a Web page should look very similar on a Mac and PC that use the same monitor.
Information about the iPhone’s gamma is a little hard to come by; I couldn’t ascertain whether it is 1.8 or 2.2. This is another reason to test your interface on an iPhone.
Final Check For iPhone UI
Your iPhone or iPod’s screen and calibration will likely be different from your Mac or PC’s screen and calibration. I often import full-screen images of the UI into iPhoto and sync them with an iPhone to see exactly how the final interface will look on the device (on Windows, you can sync photos using iTunes). This gives you another chance to make adjustments before slicing up images or committing anything to code.

This article explains how to handle the problem that while testing some landscape iPhone app interface mocks, they seem blurrier than they appear in Photoshop.
Please note: For some bizarre reason, the Photos app on the iPhone doesn’t display landscape images at 1:1. Instead, it scales them slightly or shifts them to a sub-pixel position, making the images blurrier than they should be. To avoid any issues, always save images in portrait mode (320 pixels wide by 480 pixels high) to test your user interface mockups (read more about this issue).
On Mac, moving colors between Photoshop and code can be made easier with Developer Picker, Hex Color Picker and Colors (all free).
Conclusion
Now, you’re able to move bitmap and vector images between Photoshop and Illustrator without any color shifts at all, and using any method. You’re also able to grab a color using the color picker in Photoshop, and then use the same HEX color value in your CSS, HTML, JavaScript, Flash or Objective-C code, and it will match your images perfectly. I hope this article has helped. If you have any questions, feel free to ask in the comments below.
Related posts
You may be interesting in the following related posts:
About the Author
Marc Edwards (@marcedwards) is the Director and Lead Designer at Bjango (@bjango), an iPhone app developer. Marc has been using Photoshop and Illustrator for over 12 years, designing for print, Web, desktop applications and iPhone.
(al)
© Marc Edwards for Smashing Magazine, 2009. |
Permalink |
13 comments |
Add to del.icio.us | Digg this | Stumble on StumbleUpon! | Tweet it! | Submit to Reddit | Forum Smashing Magazine
Post tags: cmyk, photoshop, rgb, workflow
Tags: cmyk, How-To, photoshop, rgb, workflow
Posted by Rick Strahl on Oct 12, 2009 in
C#,
Dotnet |
View Original Article
LINQ to SQL by default loads related entities and entity sets by using Lazy Loading. Which means if you retrieve a list of entities in a query that references other entities these other entities are not actually loaded unless you physically access them. Lazy loading is quite useful in some scenarios – typically when you load up individual instances for display purposes in simple record based UIs, but it can be a real problem when displaying list based data that needs to have access to related data. In related list scenarios it’s quite easy to have a list that has 100 records displayed on a page to fire off 100 hundred child queries to retrieve the related data – clearly in most cases that’s quite undesirable.
Lets look at an example, from my Time Trakker sample application for the LINQ to SQL business layer.
In my Time Trakker app I have time entries that can be queried. An entry has a related project and customer which in turn can be referenced through the project:
So if I have an EntryEntity I can get a project with Entry.ProjectEntity and a customer with Entry.ProjectEntity.CustomerEntity. So far so good.
Now in my businesslayer I have a routine that basically allows me to query this model for a timesheet report by passing in a bunch of report parameters via a parameter object like so:
public IQueryable<EntryEntity> GetTimeSheetByClient(TimesheetReportParameters parms)
{
IQueryable<EntryEntity> result =
from entry in Context.EntryEntities
where entry.TimeIn >= parms.FromDate &&
entry.TimeIn < parms.ToDate.Date.AddDays(1) &&
entry.PunchedOut &&
parms.Companies.Contains(entry.CustomerPk)
orderby entry.ProjectEntity.Customer.Company, entry.ProjectEntity.ProjectName, entry.TimeIn
select entry;
if (parms.BillType == "Unbilled")
result = result.Where(e => !e.Billed);
else if (parms.BillType == "Billed")
result = result.Where(e => e.Billed);
return result;
}
The parameter object has things like a date range, which type of entries to retrieve and so on which are applied against the mode in the query consecutively. This incremental building up of queries using Linq’s fluent language interface is one of my favorite LINQ features. The result of this query is then returned as an IQueryable<EntryEntity>.
When I retrieve this list of entries in the ASP.NET front end I end up databinding it and then binding to the data inside of a ListView control. The data used is mostly from the Entry Entity but there’s also some data displayed from the customer and project. Here’s what the html based report looks like:

Notice the headers which include the customer name and project name which come from related entities.
Now when the report runs it loads the report like this:
protected void ProcessReport()
{
this.ReportParameters.Companies.Clear();
foreach (ListItem item in this.lstCustomers.Items)
{
if (item.Selected)
this.ReportParameters.Companies.Add(int.Parse(item.Value));
}
this.DataBinder.Unbind();
if (this.DataBinder.BindingErrors.Count > 0)
{
this.ErrorDisplay.ShowError(this.DataBinder.BindingErrors.ToHtml(), "Please correct the following");
return;
}
IQueryable<EntryEntity> entries = this.Entry.GetTimeSheetByClient(this.ReportParameters);
// We'll dynamically load the ReportView User Control View, bind it then render
TimeSheetReport rep = this.LoadControl("~/Reports/TimeSheetReport.ascx") as TimeSheetReport;
rep.BindData(entries, this.ReportParameters);
this.RenderReport(rep);
}
then the actual binding in the report to the listview the TimeSheetReport control:
public void BindData(IQueryable query, object parameters)
{
this.Parameters = parameters as TimesheetReportParameters;
this.entryList= (query as IQueryable<EntryEntity>).ToList();
this.lstReport.DataSource = this.entryList;
this.lstReport.DataBind();
}
And finally the data is actually bound:
<asp:ListView runat="server" id="lstReport" ItemPlaceholderID="layoutContainer" >
<LayoutTemplate>
<div id="layoutContainer" runat="server" />
</LayoutTemplate>
<ItemTemplate>
<%# this.RenderProjectGroupHeader(Container.DataItem as EntryEntity) %>
<div class="itemcontainer">
<div class="itemheader"><%# Eval("Title") %> </div>
<table width="90%" cellpadding="5">
<tr>
<td valign="top" style="width:120px;"><small><%# TimeUtils.ShortDateString((DateTime) Eval("TimeIn"),true) %><br />
<%# TimeUtils.ShortDateString((DateTime) Eval("TimeOut"),true) %></small></td>
<td valign="top"><%# Eval("Description") %></td>
<td valign="top" style="width: 70px;"><%# TimeUtils.FractionalHoursToString( (decimal) Eval("TotalHours"), "{0}h {1}min" ) %></td>
</tr>
</table>
</div>
<%# this.RenderProjectFooter(Container) %>
</ItemTemplate>
</asp:ListView>
The main data displayed for each entry all comes from the Entry entity and that’s fine. However there RenderProjectGroupHeader() method figures out whether the group changed and based on this needs to access the Customer and Project information.
protected string RenderProjectGroupHeader(EntryEntity entry)
{
string output = "";
// if the project name has changed render a group as a <div> header
if (entry.ProjectEntity.ProjectName != lastProjectName)
{
lastProjectName = entry.ProjectEntity.ProjectName;
// *** New project add hours for first time
this.groupTotalHours = entry.TotalHours;
string html = string.Format(
@"<div class='groupheader'>
<div style='float:right'><small>{0}</small></div>
{1}
</div>
", entry.ProjectEntity.Customer.Company, entry.ProjectEntity.ProjectName);
return html;
}
else
this.groupTotalHours += entry.TotalHours;
this.grandtotalHours += entry.TotalHours;
return output;
}
And here you can see the child entities being accessed.
Now the report works fine with this code. But if you actually look at this SQL generated for this report you’ll find that this query causes a flurry of activity against the server:
It turns out that each access to the ProjectEntity and CustomerEntity object causes a separate query to the server (shown) for the first time a particular Project or Entity is referenced. This means for each project in the application there will be two additional queries hitting the server so if I show 20 projects I’ll hit the database 40 extra times. That’s lazy loading for you and it’s usually a problem in list based displays like this. It can be much worse if EVERY row you display requires one or more related entities.
Working around Lazy Loading in LINQ to SQL
LINQ to SQL loads related entities and entity sets using lazy loading. Oddly you can’t override this behavior either in the model – even though you can delay load individual properties (like large text, image or XML fields). So everything always lazy loads.
DataLoadOptions for Prefetching
There’s a mechanism that allows you to specify prefetching using the DataLoadOptions which looks like this when applied GetTimeSheetByClient():
public IQueryable<EntryEntity> GetTimeSheetByClient(TimesheetReportParameters parms)
{
DataLoadOptions options = new DataLoadOptions();
options.LoadWith<EntryEntity>(c => c.ProjectEntity);
options.LoadWith<ProjectEntity>(p => p.Customer);
this.Context.LoadOptions = options;
IQueryable<EntryEntity> result =
from entry in Context.EntryEntities
where entry.TimeIn >= parms.FromDate &&
entry.TimeIn < parms.ToDate.Date.AddDays(1) &&
entry.PunchedOut &&
parms.Companies.Contains(entry.CustomerPk)
orderby entry.ProjectEntity.Customer.Company, entry.ProjectEntity.ProjectName, entry.TimeIn
select entry;
if (parms.BillType == "Unbilled")
result = result.Where(e => !e.Billed);
else if (parms.BillType == "Billed")
result = result.Where(e => e.Billed);
return result;
}
This works and results in one large SQL statement that preloads the customer and project child entities.
However, this approach is problematic in a number of ways if you’re like me using a persistent data context. In my applications I scope a data context to a business object, so multiple operations may be performed against a single data context instance. If you have more than one operation that’s called and setting the DataLoad options it’s easy to clobber the settings on this object. A common problem when you have a persistent object like the DataContext and with L2S it’s difficult to get away from storing the context in some sort of persistent mechanism as it’s a connected ORM.
The fact that the options are tied to the DataContext rather than the query itself also makes it much more difficult to customize the query externally depending on the usage of the result. I often pass out an iQueryable and allow customization of the result set. Outside of the business layer the DataContext and therefore the options are not available and so it can’t be set externally.
Finally the DataOptions are tied to full related entities. If you just want to preload a property or two (like ProjectName and Company in our example here) you’re out of luck. DataOptions only deal with full entities.
Using Projection to Force Pre-Fetching
But there’s another way to write your queries differently to effectively force LINQ to SQL to prefetch by using projection in the Select clause of the LINQ statement. Basically the idea is to project the related entities or simple properties at the top level of the returned result to force the data to be denormalized and so becomes effectively preloaded.
So back to the example, if I want to load both the Project and Customer instances completely I can force the query to project into a type like this:
public class ReportEntryItem
{
public EntryEntity Entry {get; set;}
public CustomerEntity Customer {get;set;}
public ProjectEntity Project { get; set; }
}
I’m using an explicit type declaration here rather than an anonymous type because the helper methods of the report rely on an entity instance to retrieve customer and project information and an Anonymous object would not allow access of properties beyond the declared query scope. The explicit object gives me a strongly typed object I can pass around the report UI methods without resorting to Reflection. If you don’t pass the returned result around and bind it immediately the explicit type is not required which is one less thing to declare.
With the new type in place, BindData then changes the query code to look like this:
List<EntryEntity> entryList;
public voidBindData(IQueryable query, objectparameters)
{
this.Parameters = parameters asTimesheetReportParameters;
var q = query asIQueryable<EntryEntity>;
// denormalize the list so we minimize related queries
var res = from entry in q
select newReportEntryItem
{
Entry = entry,
Project = entry.ProjectEntity,
Customer = entry.ProjectEntity.Customer
};
// in this case we want a List<T> so we can lazy load more data
this.entryList = res.ToList();
this.lstReport.DataSource = this.entryList;
}
Now when the ToList() executes I get a single denormalized and very large record for each row that includes the data for Entry, Customer and Project in the generated SQL:
exec sp_executesql N'SELECT [t0].[Pk], [t0].[CustomerPk], [t0].[ProjectPk], [t0].[InvoicePk],
[t0].[UserPk], [t0].[Title], [t0].[Description], [t0].[TimeIn], [t0].[TimeOut], [t0].[PunchedOut],
[t0].[Qty], [t0].[Rate], [t0].[TotalHours], [t0].[ItemTotal], [t0].[Taxable], [t0].[Billed],
[t0].[Imported], [t0].[Xml], [t0].[tversion], [t3].[test], [t3].[Pk] AS [Pk2], [t3].[LastName],
[t3].[FirstName], [t3].[Company], [t3].[Address], [t3].[City], [t3].[State], [t3].[Zip],
[t3].[Country], [t3].[CountryId], [t3].[Phone], [t3].[Email], [t3].[Fax], [t3].[Notes],
[t3].[Entered], [t3].[Updated], [t3].[LastOrder], [t3].[BillingRate], [t3].[Xml] AS [Xml2],
[t3].[tversion] AS [tversion2], [t1].[Pk] AS [Pk3], [t1].[CustomerPk] AS [CustomerPk2],
[t1].[ProjectName], [t1].[Entered] AS [Entered2], [t1].[StartDate], [t1].[EndDate],
[t1].[Status], [t1].[tversion] AS [tversion3]
FROM [dbo].[Entries] AS [t0]
INNER JOIN [dbo].[Projects] AS [t1] ON [t1].[Pk] = [t0].[ProjectPk]
LEFT OUTER JOIN (
SELECT 1 AS [test], [t2].[Pk], [t2].[LastName], [t2].[FirstName], [t2].[Company], [t2].[Address], [t2].[City], [t2].[State], [t2].[Zip], [t2].[Country], [t2].[CountryId], [t2].[Phone], [t2].[Email], [t2].[Fax], [t2].[Notes], [t2].[Entered], [t2].[Updated], [t2].[LastOrder], [t2].[BillingRate], [t2].[Xml], [t2].[tversion]
FROM [dbo].[Customers] AS [t2]
) AS [t3] ON [t3].[Pk] = [t1].[CustomerPk]
WHERE (NOT ([t0].[Billed] = 1)) AND ([t0].[TimeIn] >= @p0) AND ([t0].[TimeIn] < @p1) AND ([t0].[PunchedOut] = 1) AND ([t0].[CustomerPk] IN (@p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14, @p15, @p16, @p17, @p18))
ORDER BY [t3].[Company], [t1].[ProjectName], [t0].[TimeIn]',N'@p0 datetime,@p1 datetime,@p2 int,@p3 int,@p4 int,@p5 int,@p6 int,@p7 int,@p8 int,@p9 int,@p10 int,@p11 int,@p12 int,@p13 int,@p14 int,@p15 int,@p16 int,@p17 int,@p18 int',@p0='2009-01-09 00:00:00',@p1='2009-10-10 00:00:00',@p2=25,@p3=2,@p4=40,@p5=41,@p6=42,@p7=15,@p8=26,@p9=45,@p10=44,@p11=16,@p12=3,@p13=24,@p14=23,@p15=4,@p16=43,@p17=39,@p18=1
Denormalized alright, but what this does is effectively provides the necessary data for all Entry, Project and Customer entities to be completely filled.
For the ListViewItem template this means that individual controls now bind to Entity.Field:
<div class="itemheader"><%# Eval("Entity.Title") %></div>
instead of just binding to the Title before. I can also directly access the project now without reloading:
<div class="itemheader"><%# Eval("Entity.Project.ProjectName") %></div>
incidentally the following also works now without another trip to the database:
<div class="itemheader"><%# Eval("Entity.Entry.ProjectEntity.ProjectName") %></div>
To demonstrate in the example, the report header function now receives the report item as a parameter and gets a repItem.Entry from it. Otherwise there are no changes in that code from before:
protected string RenderProjectGroupHeader(ReportEntryItem repItem)
{
string output = "";
EntryEntity entry = repItem.Entry;
// if the project name has changed render a group as a <div> header
if (entry.ProjectEntity.ProjectName != lastProjectName)
{
lastProjectName = entry.ProjectEntity.ProjectName;
// *** New project add hours for first time
this.groupTotalHours = entry.TotalHours;
string html = string.Format(
@"<div class='groupheader'>
<div style='float:right'><small>{0}</small></div>
{1}
</div>
", entry.ProjectEntity.Customer.Company, entry.ProjectEntity.ProjectName);
return html;
}
else
this.groupTotalHours += entry.TotalHours;
this.grandtotalHours += entry.TotalHours;
return output;
}
Note that I can still bind to entry.ProjectEntity.ProjectName and this works without another trip to the database because the Project entity was preloaded in the repItem.Project property. This the same instance that’s referenced in entry.ProjectEntity just as repItem.CustomerEntity is the same entry.ProjectEntity.CustomerEntity.
By including the Customer and Project entities as projected values in the query we’ve forced them to preload and we've reduced 40 queries to just a single (but large and redundant) query.
Watch what you Load
This example loads the full customer and project entities, but realistically we only need the Company and ProjectName fields from the respective related tables. If you know up front you only need a few of the fields in a table it’s more efficient to load just that data in the projection which has roughly the same effect. Again this is easier if you can use an anonymous type, otherwise the projected type instance has to reflect this layout.
The following is quite a bit more efficient than retrieving the full entities:
var res = from entry in q
select new ReportEntryItem
{
Entry = entry,
ProjectName = entry.ProjectEntity.ProjectName,
Company = entry.ProjectEntity.CustomerEntity.Company
};
because it reduces the amount of field data for each row of SQL result data significantly.
You have to be careful with this though – in the above scenario if I access entry.Entry.ProjectEntity.CustomerEntity.Address I will end up lazy loading both the Project and Customer records from the database. In this instance only the ProjectName and Company were retrieved, not the entire entities. IOW, if you pull just a few fields of related entities make sure you stick to using only those fields and leave the actual related entities alone.
To Lazy Load or Not to Lazy Load
Arguably LINQ to SQL’s lazy loading functionality behavior without override ability is not exactly intuitive, but it’s not terribly complex to force it to return pre-loaded data either. It does require some foresight as switching between lazy loaded and pre-loaded entities effectively requires some code changes to reflect the project type’s structure. It would be much nicer if there was syntax that would let you specify a prefetch path right on the query (something I really like about llblGen’s LINQ implementation).
Also keep in mind that lazy loading isn’t always bad so this isn’t something that should be done on every query. Denormalized data retrieves a lot of repetitive data so you’re often sacrificing data on the wire for fewer round trips to the database. In many situations – especially record level CRUD operations – lazy loading is usually a great way to go. Even small list based displays might not suffer severely from many requests to retrieve data vs. running a single query to retrieve the data you need. Also keep in mind that child items don’t necessarily load for EACH and every row, but only the first time a particular instance is loaded, whereas a denormalized query ALWAYS retrieves the related data for every row. So a list with a lot of repeated related data may not actually access the database as often as you might thing. It’s a tradeoff and experimentation is required to see what works best in each situation. But with a little bit of extra work you can make L2S do what you need it to.
© Rick Strahl, West Wind Technologies, 2005-2009

Tags: LINQ
Posted by Rich Tretola on Oct 12, 2009 in
Flex |
View Original Article
Adobe has announced that the browser based Flash player 10.1 will soon be running on every major mobile platform (Windows Mobile, Android, Blackberry, Symbian, WebOS) except Apple's iPhone. (See my opinion on Apple here). They also announced that although Apple...
Tags: flashplayer, iphone, Mobile, News & Events