Wednesday, August 06, 2008

Even though I seem to have gotten it right when I wrote about this in my book (I just checked) in my own memory I have had a misconception about GetObjectbyKey.

I thought that GetObjectbyKey and TryGetObjectbyKey only searches the cache for entities that already have been created. But I realized this morning that if it doesn't find the entity in the cache, it will create a query and go look in the database also.

dim myEntity=context.GetObjectbyKey(myKey)

or use one of the methods for creating an EntityKey on the fly.

Dim cust=context.GetObjectbyKey(new EntityKey("NorthWindEntities.Customers","CustomerID",3)

You can easily make this a generic method if you needed to.

Compare this to a query

Dim cust= (From c in context.Customers Where c.CustomerID=3).FirstorDefault

or

Dim cust=context.Customers.Where(Function(c) c.CustomerID=3).FirstorDefault

Using GetObjectbyKey vs. a query is not just about coding because they work very differently.

When you execute a query, EF will always go to the database first and retrieve whatever it finds. As it's loading the results into the cache, if the entity already exists in the cache, it will refresh that entity based on the MergeOptions.

  • If MergeOption is AppendOnly (this is the default) then the newly retrieved entity will disappear into the ether.
  • If it is OverwriteChanges, then the values from the server will replace the current values of the entity in the cache.
  • If it is PreserveChanges, the values from the server will replace the original values of the entity in the cache. The current values won't be touched.
  • MergeOption can also be set to NoTracking. That's an interesting scenario because it will create a second instance of this object. I'm not sure how I feel about that yet. However, if you already have an entity in memory but not in the cache, GetObjectbyKey will have the same effect. It won't find the entity in the cache and will go get one and put it into the cache - result is two instances of the entity.

So depending on your needs, GetObjectbyKEy (and TryGetOBjectbyKey) is very efficient because it won't go to the database unless it has to, however it won't refresh your data from the server as a query would.

Good to know so I can make the right choice when the time comes.

Wednesday, August 06, 2008 8:05:19 AM (Eastern Standard Time, UTC-05:00)  #     |  Comments [4]  | 
 Tuesday, August 05, 2008

I am copying (and slightly modifying so that it is not out of context) a forum post that I wrote to put here in my blog. Here's the original thread if you are interested.

When working with object services, you can query data using  LINQ to Entities or ObjectQueries with Entity SQL.

Unless you specifically use LINQ syntax in your EF query,  it will be an ObjectQuery.

An example.

context.Customers  is an ObjectQuery. The same as context.CreateQuery<Customer>("SELECT c FROM myentitycontainer.Customers as c") or even context.CreateQuery<TEntity>(entitySetNameString) if you want to do this generically as Graham Hay shows earlier in this thread.

from cust in context.Customers blah blah is a LINQ to Entities query.

The first example (return context.Customers) however takes advantage of EF's query builder methods which will literally construct a nice ESQL query and create an objectQuery for you. There are not a lot of ESQL Query Builder methods but some of them overlap with LINQ methods.

Check out the difference here:

var q1=context.Customers.Where("it.FirstName='Julie'")

var q2=context.Customers.Where(c=>c.FirstName=="Julie")

The first uses a query builder method and ESQL syntax in the where parameter, therefore EF will know that you are using the Where Query Builder method, not the LINQ to Entities one. But the second uses a lambda so EF knows that's LINQ.

At run time, after the first line of code has been executed (not the executing the query, just the creating q1), you can debug q1 and see that it is an ObjectQuery<Customer> and that it has a command text value that is an ESQL Query

"SELECT VALUE it\r\nFROM (\r\n[Customer]\r\n) AS it\r\nWHERE\r\nit.FirstName='Julie'"

Because the second query has some very specific LINQ to Entities syntax in it, EF determines that this is a LINQ to Entities query. When debugging Q2, the value of q2 will be an objectQuery<Customer> but the TYPE of Q2 will be a System.LINQ.IQueryable. The CommandText property is empty.

LINQ to Entities and ObjectQuery queries are processed differently as well. The first few steps for each are unique to the query method, then at some point in the query pipeline, they meet on a common path.

Don't discount ObjectQuery as a query option because it is that class that allows you to more readily use generics and build dynamic queries.

To use generics in a real LINQ to entities query, you would probably have to do functional programming.

This is why ObjectQueries are so powerful. You can use generics with them. You can build queries dynamically.

But don't expect to do it using the strongly typed classes. Use CreateQuery or new ObjectQuery and then pass in the generic type (e.g. TEntity) and the Entity SQL string.

Tuesday, August 05, 2008 10:21:07 AM (Eastern Standard Time, UTC-05:00)  #     |  Comments [0]  | 
 Monday, August 04, 2008

This weekend's passing of Alexander Solzhenitsyn prompted me to think about my senior year in college. I was a history major with a concentration in Russian History (and had no clue what a hash table was by the time I graduated). My senior thesis was a comparison of the experiences of political prisoners under the Tsarist regime of the late 19th/early 20th centuries, to those of the political prisoners of the Stalinist era. The irony is that it was the political prisoners of the first that led the revolution which over time, resulted (indirectly) in Stalin coming to power. And Stalin cast a much broader net when defining his enemies.

My research mostly took the form of reading published diaries. Many of them. Solzhenitsyn's writings about the labor camps was definitely an invaluable resource.

So if you can imagine my days and nights for months and months spent in a dark corner of the library reading these harrowing personal accounts.

In addition to my other classes, that semester I was the photo editor for the college yearbook.  When I wasn't in classes and wasn't reading the depressing diaries, I spent endless hours in a darkroom processing film and printing  photos. The only radio station that I could receive in the darkroom (remember this was the early 80's so our media options were pretty limited) was one that played golden oldies from the 1940's. This was apropos since the this is the time of the Stalinist labor camps.

So all in all it was a very dark 4 months in my life, not only literally dark, but filled with doom, gloom and hopelessness and living in the past.

What I never knew until his death yesterday, was that he, too lived in Vermont. From 1976 to 1990 when he returned to his homeland, he lived in the tiny town of Cavendish in Southern Vermont.

Monday, August 04, 2008 7:51:11 AM (Eastern Standard Time, UTC-05:00)  #     |  Comments [0]  | 
 Saturday, August 02, 2008

sampleappI remember seeing WPF/E, the early version of what was to become Silverlight, at Microsoft a few years ago, then running over to the building where the TabletPC team lives and asking if the WPF inking features were going to be in Silverlight. As you may or may not know by now, the answer was yes and it is the InkPresenter control in Silverlight that enables drawing in Silverlight apps. I had been doing a lot of work with Ink on the Web and was frustrated by the limitations and challenges of dealing with ActiveX. Putting the capabilities into Silverlight not only mean very easy deployment, but it removed the restriction for TabletPC O/S or even a Windows O/S, as well as a dependence on Internet Explorer.

I have presented this technology at various conferences - generally to a small audience. I am always surprised that more people aren't interested in it. Are we really just Tablet PC Freaks?

Even the Silverlight books don't devote very much time to the InkPresenter.

Well a few more people are going to be exposed to this now because this months MSDN Magazine (August 2008) has an article about using the InkPresenter that I wrote. (The issue features a bunch of Silverlight articles and an Astoria article too!) The article not only shows how to get the InkPresenter to do it's inky thing, but also how to take advantage of web services to persist and retrieve drawings as well as to do hand writing recognition. The latter, as I discovered when I put my sample up on my web site, requires that the service be hosted on a computer that has the Recognition Engines installed. If you have a TabletPC or Windows Vista, they are already there. Otherwise, you need to install them on the host. Unfortunately, my own web site is on a shared server, so installing the reco engines is not an option.

I've also learned that even though the reco is in Vista, and the Speech Engines made it into Windows 2008 Server, the hand writing reco engines did not.

The article (and the sample) uses Silverlight 2.0, LINQ to SQL, LINQ to XML and WCF Services so it was fun to use so many new technologies. I originally did the work in Silverlight 1.0 with Javascript so it can be done, just a little harder. I guess the next step would be to replace the LINQ to SQL and WCF with Astoria but that's for another day.

You can get the engines here: MS Windows XP Tablet PC Editions 2005 Recognizer Pack.

The article: Write On! Create Web Apps You Can Draw On with Silverlight 2

The sample application for Silverlight 2.0 (without the recognition until I move the WCF Service elsewhere) : http://www.thedatafarm.com/Silverlight/AnnotationMSDN/.

Unfortunately, drawing is not one of my skills, so some of the screenshots in the article are laughable, but hey, whadya want? :-)

(Oh and I'm not responsible for that very first sentence. But as Kathleen says: We Don't Publish Words, We Publish Ideas - Get Over It)

Have fun!!

Saturday, August 02, 2008 12:12:37 PM (Eastern Standard Time, UTC-05:00)  #     |  Comments [1]  | 
 Friday, August 01, 2008

dragon1

This weekend is the third DragonHeart Dragon Boat race on Lake Champlain in Burlington. This will be my second year paddling in the event on a team called the Dragonflies, made up of 20+ friends - all women. There are 80 teams in the event. Most of them are community teams that have no more practice time than the single practice paddle that the event organizes in July, so we're mostly just winging it and not really that competitive. There are amateur teams that own their own boats and participate in races all over the world. We'll even have to compete against them in our first two (and maybe only two) heats.

The real DragonHeart teams are made up of  breast cancer survivors. The event is a fundraiser for their organization and another organization of their choice, which is Vermont's "Cancer Patient Support Program’s Emergency Fund" this year.

It's an amazing day and there are over 2000 participants (80 teams * 20 per team) and thousands of spectators. Hopefully we'll luck out with the weather.

Our team's first paddle is at 9am. Early pearly.

Friday, August 01, 2008 2:45:34 PM (Eastern Standard Time, UTC-05:00)  #     |  Comments [1]  | 
 Wednesday, July 30, 2008

I have been writing gobs of Extension methods for entity Framework through the course of writing my book.

I was inspired by this forum thread to create extension methods to overload existing methods in the APIs.

One pattern that was annoying me was that frequently when I'm using the GetObjectStateEntries method of the ObjectStateManager, I want to filter on a type. It only meant building a linq expression with the method in it

Dim CustomerEntries= From entry _
                                    In objStateMgr.GetObjectStateEntries(EntityState.Added Or EntityState.Deleted _
                                          Or EntityState.Modified Or EntityState.Unchanged) _
                                    Where entry.Entity.GetType Is Customer

So two things about this were bugging me.

The first is I always have to list out all of those entries. Sometimes I only want one or two, so it's good to build the list.

The second is that I always have to write a query.

So, I created a few overloads to the method.

The first takes no parameters, and returns all of the entries, regardless of EntityState

<Extension()> _
Public Function GetObjectStateEntries(ByVal osm As Objects.ObjectStateManager) _
   
As IEnumerable(Of Objects.ObjectStateEntry)
  Dim typeEntries = From entry As Objects.ObjectStateEntry _
                  
In osm.GetObjectStateEntries(EntityState.Added Or EntityState.Deleted _
                      Or EntityState.Modified Or EntityState.Unchanged)
  Return typeEntries
End Function

Now I can just call GetObjectStateEntries and get all of them without having to specify the four entity state enums.

The second returns all objects of a particular type. Having the overload for the generic type is more discoverable for people like me.

<Extension()> _
Public Function GetObjectStateEntries(Of TEntity)(ByVal osm As Objects.ObjectStateManager) _
    
As IEnumerable(Of Objects.ObjectStateEntry)  
  Dim typeEntries = From entry As Objects.ObjectStateEntry _
                    In osm.GetObjectStateEntries(EntityState.Added Or EntityState.Deleted _
                      Or EntityState.Modified Or EntityState.Unchanged) _
                    Where entry.Entity Is TEntity

  Return typeEntries 
End Function

Now I can get all entities of a particular type without having to build a query.

GetObjectStateEntries(Of Customer)

The last takes the EntityState parameters and filters on a particular type.

<Extension()> _
Public Function GetObjectStateEntries(Of TEntity)(ByVal osm As Objects.ObjectStateManager, _
         ByVal state As EntityState) As IEnumerable(Of Objects.ObjectStateEntry) 
  Dim typeEntries = From entry As Objects.ObjectStateEntry _
                    In osm.GetObjectStateEntries(state) _
                    Where entry.Entity Is TEntity
  Return typeEntries
End Function

So I can use GetObjectStateEntries it's "normal" way, except I can include the type as well as filtering on state.

GetObjectStateEntries(Of Customer)(EntityState.Unchanged)

(These are in Chapter 14 along with their C# versions. :-))

Wednesday, July 30, 2008 9:21:05 AM (Eastern Standard Time, UTC-05:00)  #     |  Comments [0]  | 
 Monday, July 28, 2008

My friend's husband is a biologist and researcher at Cornell's Ornithology Lab and pretty well known in his field.

NPR played some clips that he recorded in Guatemala of Howler Monkeys and Toucan's on their feature, Sounds from the Wild. Cool.

Monday, July 28, 2008 12:08:54 PM (Eastern Standard Time, UTC-05:00)  #     |  Comments [1]  | 

Yesterday I made my third attempt of the summer to get up the the 2.75 mile climb of the App Gap. I have to ride uphill 3 miles just to get to the "starting point".

Here's what the elevation looks like from the starting point to the peak.

The first arrow is where I've bailed previously (twice). The second is about where I got to last night (2.5 miles). The yellow line is the peak. You can see that the last bit is a freaking wall.

appgap

I almost bailed at the same spot again last night but goaded myself to the next sign (50 ft away) then to the end of the guard rail (another 100 ft) and then to the picnic tables (another 200 ft). Then once I got past the picnic tables, it eased up again and I got all the way to the last wall, but there was just no way I could do the last little bit. Now that I realize that it gets easier past that first spot, I can definitely push myself through it again.

However, since I had started out hoping to just get past my last bail point and maybe to the picnic tables, I was surprised to get as far as I did. I wasn't the least bit disappointed not to get to the top because that wasn't my goal.

On the way up, I saw my neighbor, Joe, flying down on his bike. He does the gap ride all the time. It's not big deal at all for him. :-) It's his little ride for when he doesn't have time to go out for a real ride.

One of the things that helped me was deciding to just go right up into my granny gear at the start - save my strength, not my gears.

Okay back to work.

Monday, July 28, 2008 9:32:03 AM (Eastern Standard Time, UTC-05:00)  #     |  Comments [2]  | 

While I continue to enjoy being at home in Vermont for the whole summer, I have to look past this fantasy to the reality of my upcoming travel where I get to share the Entity Framework (and Silverlight) love around the world. I have yet to get this all onto my website schedule.

Here's what's on my schedule:

I'm also planning to attend Microsoft's PDC 2008 in Los Angeles

Then I will rest up for the winter in Vermont. :-)

Monday, July 28, 2008 7:22:48 AM (Eastern Standard Time, UTC-05:00)  #     |  Comments [0]  | 
 Saturday, July 26, 2008

There are two web apps based on mapping APIs - one uses Google and the other uses Virtual Earth - that I use frequently. It's a long way from what you could do with Virtual Earth when I started dabbling when it first came out. Read more.

[A New DevLife Post]

Saturday, July 26, 2008 7:00:49 PM (Eastern Standard Time, UTC-05:00)  #     |  Comments [0]  | 

Mike has posted a bunch of ADO.NET Data Services videos up on Channel 9.

Even though I haven't had a chance to check them out yet, it's easy to presume that these are going to be as great as all of his other screencasts.

http://channel9.msdn.com/tags/UK

He says there are more to come.

Enjoy.

Saturday, July 26, 2008 12:11:01 PM (Eastern Standard Time, UTC-05:00)  #     |  Comments [0]  | 
 Friday, July 25, 2008

I learned a neat ESQL trick from Danny Simmons today.

The most basic Entity SQL expression is one that would simply query for a single entity with no filters, no projection etc.

context.CreateQuery<Customer>("SELECT VALUE con FROM MYEntityContainer.Contacts AS con")

You can actually express the string using only the target collection:

context.CreateQuery<Customer>("MyEntityContainer.Contacts")

and EF will build the same command tree as it does for the first expression.

Friday, July 25, 2008 8:45:30 PM (Eastern Standard Time, UTC-05:00)  #     |  Comments [0]  | 

Software Developer

Vertek Corporation, a leading provider of telecommunications services located in Colchester, Vermont is seeking a Software Developer to join our growing Software Development team.

The Software Developer will support our existing products and help Vertek build our next generation workflow platform which leverages Red Hat’s jBPM workflow engine with a Google Web Toolkit (GWT) Web 2.0 presentation framework. The ideal candidate will have full/hands-on SWDLC experience designing, building, testing, deploying and supporting n-tier applications. Candidates should have experience with two or more of the following technologies: GWT, JBoss, JUnit (or NUnit), Hibernate, Subversion, .NET, Business Objects (universe creation). They should have hands-on experience with all of the following: n-Tier development, SQL Server 2000+ and/or Oracle 10g, Java, Eclipse, Ant and web development. Experience developing large scale/enterprise applications in a Continuous Integration environment is a plus.

Required experience and education: 1-3 years, bachelor’s degree in computer science or related discipline (relevant co-op experience may be applied). Java, Oracle and/or Microsoft certifications are a plus.

E-mail resume to: HR@Vertek.com

Friday, July 25, 2008 8:20:50 PM (Eastern Standard Time, UTC-05:00)  #     |  Comments [0]  | 

Kathleen Dollard is building a list for C# devs who are going to be building projects in VB. Read more

[A New DevLife Post]

VB
Friday, July 25, 2008 2:14:49 PM (Eastern Standard Time, UTC-05:00)  #     |  Comments [2]  | 
 Friday, July 18, 2008

I'm just a little busy so I'll probably skip this little run...

The Vermont 100

Friday, July 18, 2008 9:06:58 AM (Eastern Standard Time, UTC-05:00)  #     |  Comments [0]  | 
 Tuesday, July 15, 2008

I have finally finished what has been, so far, the most difficult chapter of my book. It is a chapter about Relationships and Associations in the Entity Framework. Relationships as a first class citizen in an API is a pretty novel thing for me (and many) and judging from the percentage of questions in the forum about relationships, I think it's one of the most confusing and complicated pieces of the framework. Complexity is not a bad thing, and it certainly is a fascinating adventure. There are so many rules that exist in order to maintain the integrity of the relationships so that they can do their work. And many of the rules are far from intuitive.

I've been struggling to understand what's behind all of these rules so that don't have to be rules to be memorized but instead become logical ways for me to work with entities. Then the job was to try to digest that and explain it in a way that is comprehensible to others. It has meant a lot of research, digging through the forums relentlessly,  reading blogs and lots and lots and lots of experimenting. Because there's really not much else out there. Oh and of course bugging the hell out of Danny Simmons and some other saints on the EF team.

The scary part is that every time I opened up door of understanding, I discovered a host of new things that I realized needed explaining as well.

I finally had to let it go and "throw it over the wall" to the reviewers.

I feel like I deserve it to be all downhill from here, but somehow I just don't think it's going to work out that way!

Tuesday, July 15, 2008 9:46:05 PM (Eastern Standard Time, UTC-05:00)  #     |  Comments [0]  | 
 Monday, July 14, 2008

Bill McCarthy's latest garden post made me realize I hadn't taken any pics in a while so here's what's going on in mid July.

The hostas are blooming.

veggiepatch 001 

The clematis are lush.
summer visit 010

There's a lot going on in the front garden - rubekia, foxglove, daisies, mallow, astilbe, roses, russian sage and so much more.summer visit 011

The Hollyhocks are starting to open.

summer visit 014

Down by the road the menarda (bee balm) is open all along the fence. summer visit 017

summer visit 016

For some reason the daylilies along the fence haven't opened while they have opened everywhere else.

summer visit 018

I'm not sure how this sunflower got into the hanging basket, but I'll have to get it out of there soon!summer visit 028 

 veggiepatch 002

The veggie garden needs major weeding but it's lush with veggies - though we're only getting lettuce (still) and waiting for everything else to come into season. Here are some peas that are getting ready. There's plenty more but the weeds are too embarrassing, so no more pictures.veggiepatch 003

Monday, July 14, 2008 3:21:34 PM (Eastern Standard Time, UTC-05:00)  #     |  Comments [1]  | 

But it didn't make Money's top 100 list because they only looked at cities with population of 50,000 - 300,000. Here's their criteria.

Burlington is a little under 40,000.

Kathleen Dollard's home town of Ft. Collins CO was #2 on the list.

But I still think Burlington is one of the best small cities in the U.S, but since we like to keep it that way (small) maybe it's better that we weren't on the list after all. ;-)

Unfortunately, there are other factors that might kept us out of the top of that list had the population filter not excluded us. The cost of living here is higher than average especially when you put it next to the salaries.

But the quality of life is what we're here for and we all make due the best we can.

Monday, July 14, 2008 8:21:27 AM (Eastern Standard Time, UTC-05:00)  #     |  Comments [1]  | 
 Sunday, July 13, 2008

Someone posted a question in the Entity Framework MSDN forum asking for an example of overriding SaveChanges. I thought I had posted one in an early thread but couldn't find it. Nor could I find an obvious example anywhere on the web, so I thought I would put one here on my blog.

There aren't a lot of public events on the classes created from the code generated classes of an Entity Data Model. But you can override the ones that exist.

ObjectContext exposes SavingChanges.

EntityObjects expose PropertyChanged and PropertyChanging and there's a pair of these for each property in an entity. E.g. for Customer, you'll get OnCustomerIDChanged and OnCustomerIDChanging.

Because these are all partial classes, you need only to create new code files that extend the partial classes. I create a separate code file for each class.

In my sample project which hosts a model for AdventureWorks, therefore, I have a code file named AWEntities (.vb or .cs) that extends the AWEntities class.

Here's an example of that class, which does a few things to my entities when I call SaveChanges before SaveChanges actually pushes the data up to the server. In this sample, I update the ModifiedDate field for Modified Customer entities, then I do the same for new ("Added") Customer Entities as well as create new default password data.

Namespace MyAssemblyNamespace

  Partial Public Class AWEntities

    Private Sub AWEntities_SavingChanges(ByVal sender As Object, ByVal e As System.EventArgs)  _
              Handles Me.SavingChanges

      'find all entities whose state is Modified so that I can 
      '
update the Customer's ModifiedDate property

      Dim changedEntities = _
      Me.ObjectStateManager.GetObjectStateEntries(EntityState.Modified)

      For Each stateEntryEntity In changedEntities
        If TypeOf stateEntryEntity.Entity Is Customer Then
          Dim cust As Customer = cType(stateEntryEntity.Entity,Customer)
          cust.ModifiedDate = Now  'update the ModifiedDate
        End If
      Next

      'make sure new entities get modifiedDate and non-nullable fields populated
      Dim addedEntities = _
      Me.ObjectStateManager.GetObjectStateEntries(EntityState.Added)
      For Each stateEntryEntity In addedEntities
        If TypeOf stateEntryEntity.Entity Is Customer Then
          Dim cust As Customer = cType(stateEntryEntity.Entity,Customer)
          cust.ModifiedDate = Now
          'password hash cannot be null
          'for demo purposes just put a default string in there
          cust.PasswordHash = MyCustomMethodtoHashStrings("
p@ssword")
          'customer table also needs salt for hash
          cust.PasswordSalt = MyCustomMethodtoCreateRandomSaltBytes()
        End If
      Next
    End Sub

  End Class
End Namespace

(7/14: adding the base of the C# partial class as a few people have asked...)

For C#, you need wire up the event handler which you can do when the OnContextCreated event is hit.

namespace MyAssemblyNamespace
{
    public partial class AWEntities
    {
        partial void OnContextCreated()
        {
            this.SavingChanges += new System.EventHandler(mySavingChanges);
        }


        public void mySavingChanges(object sender, System.EventArgs e)
        {
            //saving changes logic
        }

    }

}

Sunday, July 13, 2008 10:27:34 AM (Eastern Standard Time, UTC-05:00)  #     |  Comments [0]  |