Natural Language Parsing

I wanted to go back to a project that I started working on <gulp> three years ago. There is a great website called the Efanchiser that translates English into Jive/VallyGirl/Sweedish Chef. There are some knock-off sites like this one, but I prefer the original. When you go through the header file (written in C) of the translation methods (not the page’s html), you can see this comment:

/* chef.x - convert English on stdin to Mock Swedish on stdout * * The WC definition matches any word character, and the NW definition matches * any non-word character. Two start conditions are maintained: INW (in word) * and NIW (not in word). The first rule passes TeX commands without change. * * HISTORY * * Apr 26, 1993; John Hagerman: Added ! and ? to the Bork Bork Bork rule. * * Apr 15, 1992; John Hagerman: Created. */

Some guy at AT&T back in the 80s came up with the code – check out this comment for the language parsing. Looks like Google and Microsoft weren’t the 1st to come up with the idea about parsing English speech 😉

/* Copyright (c) 1989 AT&T */ /* All Rights Reserved */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */ /* The copyright notice above does not evidence any */ /* actual or intended publication of such source code. */

The actual .c file has the logic like this:

# line 28 "chef.l" { BEGIN NIW; i_seen = 0; printf("%c\nBork Bork Bork!",yytext[0]); } break; case 4: # line 31 "chef.l" ECHO; break; case 5: # line 32 "chef.l" ECHO; break; case 6: # line 34 "chef.l" { BEGIN INW; printf("un"); } break; case 7: # line 35 "chef.l" { BEGIN INW; printf("Un"); } break; case 8:

Basically, it is one big Select…Case statement with certain words/phrases replaced and throwing the words “Bork Bork Bork” at the end. The implementation uses word positioning like this:

0}; # define YYTYPE unsigned char struct yywork { YYTYPE verify, advance; } yycrank[] = { 0,0, 0,0, 1,7, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 1,8, 9,34, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 15,39, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 15,0, 0,0, 39,0, 0,0, 1,7, 1,9, 0,0, 0,0, 0,0, 0,0, 0,0, 1,10, 0,0, 0,0, 0,0, 0,0, 0,0, 3,7, 0,0

Which is pretty cool but really hard to duplicate or extend.

I wanted to add an old-english translator. Instead of adding to the C++ project, I thought of creating a WCF Service that creates an Old-English translation using C#.

My first step was to find a natural language parser that can break the input sentence into its words and tag each word as a part of speech. A quick bing search found a couple of options:

· This site has what I am looking for – but he does not expose the tokenizing as a web service or provide the API source code. I really am not interested in parsing the html so I moved on.

· The Sharp Natural Language Parser (SNLP) found on the codeplex seems to fit the bill – but it is complex to implement and it is a very brittle solution – it relies on a third party library called Maximum Entropy Models (MEM) that has to have a certain folder structure created. The SNLP has a database alternative (called Wordnet Lexical Database) but that link is not working.

· This site has what I am looking for – but he wants to charge a fee to use it. No thanks.

· There is another codeplex project that uses Pyton called ConceptNetUtils found here. I really don’t want to learn Python for this.

There are more hits, but the quality of the sites gets worse and worse.

Biting the bullet, I decided to use the SNLP project from codeplex and therefore use the MEM on my local file system. A great example is found here. Perhaps as a follow up project I will abstract the MEM from the file system. I did have to peek at the MEM to see if it would be an easy port – here is one of the files in notepad:

image

Bummer – looks like that project will be harder said than done….

So I added the directories to my source folder and hit F5 – sure enough it worked. I then started to dive into the examples and see how the API was structured. That is the subject of my next post.

To get an idea of how to make an English phrase an old English phrase, I turned to Bing. There are a couple of sites that translate individual words (like this one). I also got a laugh because there are TONS of sites that willtranslate Shakespeare to modern English – doubtlessly helping High School English students everywhere.

There are a couple of components:

· Rearrange the sentence structure as recommended here

· Find..replace certain words/phrases as found here

There are obviously other things I could do to make the Old English better, but I thought I would start with the basics.

.NET 4.0 Upgrade Exams–> Here I Go Again….

I have started studying for my .NET 4,0 upgrade exams: Exam 70-521 and Exam 70-523.  I read the subjects covered on the Microsoft exam website and it is obvious that they are covering more of the >NET 3.0, 3.5, and 4.0 framework than before.  For example, there is much more of an emphasis on LINQ and WPF than the 3.5 upgrade exam.

Diving into LINQ, I realized there is TONS I don’t know about –> SelectMany, Joining Tables, etc… As for WPF, I am coming up to speed on the basic syntax –> like what is the difference between a TextBox and a TextBlock.  The exam guides should be coming in the next couple of days.  Between that and the on-line Microsoft resources, I should be ready.

Polymorphism In Action

The swim team that I help out with is purchasing a timing system. The timing system’s data needs to interface with the existing datamart, which is stored in a SQL Server database. The database serves a variety of functions – from season registration, meet registration, team records, etc…

The system that the board chose is the industry leader with its own proprietary data storage mechanism. Their system does not allow any kind of RPC from a RDBMS system. The only way to get into and out of the system is via text files. These text files are structured using USA Swimming’s Standard Data Interchange Format – found here with a simplified version found here. I cracked open the RFC and was amazed – they are not using XML! Rather, it is a flat file format with each row of data conforming to certain field lengths. It is like going back to FORTRAN programming – without the sexiness of the green screen. Here is an example of a row of data:

D01 Whitaker, Taylor 122691TAY*WH 1226199118FF 1003 UNOV 1:25.00Y

And here is how the RFC tells you how to parse the payload:

Start /
Length Mandatory Type Description
1/2 M1* CONST "D0"
3/1 M2* CODE ORG Code 001, table checked
4/8 future use
12/28 M1 NAME swimmer name
40/12 M2 ALPHA USS#
52/1 CODE ATTACH Code 016, table checked
53/3 CODE CITIZEN Code 009, table checked
56/8 M2 DATE swimmer birth date
64/2 ALPHA swimmer age or class (such as Jr or Sr)
66/1 M1 CODE SEX Code 010, table checked
67/1 M1# CODE EVENT SEX Code 011, table checked
68/4 M1# INT event distance
72/1 M1# CODE STROKE Code 012, table checked
73/4 ALPHA Event Number
77/4 M1# CODE EVENT AGE Code 025, table checked
81/8 M2 DATE date of swim
89/8 TIME seed time
97/1 * CODE COURSE Code 013, table checked

Therefore, to interface with our SQL Server database, I need a way of translating the data that is in the database into the structured format (and back again).

There are a series of files – A0, B1, etc… I was thinking of making a class that is a concrete implementation of the RFC for that row of data. I then realized that I could use the power of an Object Oriented Language to make my solution less brittle and to try out some cool polymorphic techniques.

My first step was to create an Interface that handles each chunk of data. Just because USA Swimming isn’t going to use XML, it doesn’t mean I can’t use XML language syntax – heck it is all structured data.

I started with the attribute:

public interface IAttribute { int AttributeId { get; set; } int Start { get; set; } int Length { get; set; } bool Manditory { get; set; } AttributeType AttributeType { get; set; } string Description { get; set; } string AttributeValue { get; set; } string PaddedValue { get; } }

The AttributeValue is a string implementation of the value of the property. The PaddedValue is the same value with the padding and left/right justification applied.

I then thought about how I wanted to implement the 15 or so different elements (called “records”, which has nothing to do with swim meet records. Someone didn’t understand the importance of domain-specific language). Since the elements are fairly stable, I went with a Strategy Pattern.

Each element is a collection of Attributes. Therefore, I created one to see if I was barking up the right tree:

public class FileDescription: Collection<IAttribute> { public string ElementId { get { return "A0"; } } public string ElementDescription { get { return "File Description Record"; } } public FileDescription() { this.Add(new Attribute { AttributeId = 1, Start = 1, Length = 2, Manditory = true, AttributeType = AttributeType.CONST, Description = "A0"}); this.Add(new Attribute { AttributeId = 2, Start = 3, Length = 1, Manditory = false, AttributeType = AttributeType.CODE, Description = "ORG Code 001, table checked" }); this.Add(new Attribute { AttributeId = 3, Start = 4, Length = 8, Manditory = false, AttributeType = AttributeType.ALPHA, Description = "SDIF version number (same format as the version number from the title page)" }); etc… } }

I then realized that there is no easy way to get the correct Attribute from the collection except via its index number. Holding my nose, I then created a new unit test to see if I could create a fake for this class. The first test passed. I then wanted to add a ToString() override that spits out the FileDescription’s values – as if I was writing it out to the flat file. Here is what I came up with:

public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(this[0].AttributeValue); stringBuilder.Append(this[1].AttributeValue); … stringBuilder.Append(this[12].AttributeValue); return stringBuilder.ToString(); }

I then realized that I would have to duplicate this code in every class that implements the Collection<IAttribute> I then created an abstract class to handle some of this work for me:

public abstract class Record : Collection<IAttribute> { public string RecordId { get { return this[0].AttributeValue.ToString(); } set { this[0].AttributeValue = value; } } public string OrganizationCode { get { return this[1].AttributeValue.ToString(); } set { this[1].AttributeValue = value; } } public const int MaxRecordLength = 160; public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); foreach (Attribute attribute in this) { stringBuilder.Append(attribute.AttributeValue); } return stringBuilder.ToString(); } public string ToPaddedString() { int padLength = 0; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(ToString()); padLength = MaxRecordLength - stringBuilder.Length; for (int i = 0; i < padLength; i++) { stringBuilder.Append(string.Empty); } return stringBuilder.ToString(); } }

I then changed the concrete classes to inherit from the Record class. I finished my Fake for the unit tests like this:

file[0].AttributeValue = "A0"; file[1].AttributeValue = "1"; file[2].AttributeValue = "V3"; file[3].AttributeValue = "20"; file[5].AttributeValue = "Hy-Tek, Ltd"; file[6].AttributeValue = "6.0X"; file[7].AttributeValue = "Hy-Tek, Ltd -USS"; file[8].AttributeValue = "252-633-5177"; file[9].AttributeValue = "02172011";

I then realized that I hate working with indexers so I added properties that give a friendly name to the indexer:

public string SoftwareName { get { return this[5].AttributeValue.ToString(); } set { this[5].AttributeValue = value; } }

I then rewrote my Fake and still got green on the unit tests.

file.RecordId = "A0"; file.OrganizationCode = "1"; file.SDIFVersionNumber = "V3"; file.FileCode = "20"; file.SoftwareName = "Hy-Tek, Ltd"; file.SoftwareVersion = "6.0X"; file.ContactName = "Hy-Tek, Ltd -USS"; file.ContactPhone = "252-633-5177"; file.FileCreation = "02172011";

Tests were still green, so I feel good.

I then wanted to tackle the actual values that will be assigned to each attribute. There are two kinds of values – the value that come from the database (three is you want to count the .NET types versus the SQL Server ones) and the one that comes from/goes into the output file. The output file is a structured string file so perhaps I can just store the Value as a string and translate it into the native types. I would need a Translation Factory that takes the native types and pushes it into the string correctly – which seems like the right thing to do.

Before creating the Translation class , I created the classes that represent the data in the SQL Server database. I chose using EF.

I then added the Translation class that takes all of the datafrom the EF classes, translates it, and sticks it into the SDIF format. An example looks like this:

public List<IndividualEvent> CreateIndividualEventRecords(int meetId) { List<IndividualEvent> individualEvents = new List<IndividualEvent>(); IndividualEvent individualEvent = null; using (HurricaneEntities context = new HurricaneEntities()) { var q = from mea in context.tblMeetEventAssignments .Include("tblMeetEvent") .Include("tblMeetEvent.tblRaceStroke") .Include("tblMeetEvent.tblAgeGroup") .Include("tblMeetSwimmerCheckIn") .Include("tblMeetSwimmerCheckIn.tblSwimmerSeason") .Include("tblMeetSwimmerCheckIn.tblSwimmerSeason.tblSwimmer") where mea.tblMeetSwimmerCheckIn.MeetID == meetId select new { FirstName = mea.tblMeetSwimmerCheckIn.tblSwimmerSeason.tblSwimmer.FirstName, LastName = mea.tblMeetSwimmerCheckIn.tblSwimmerSeason.tblSwimmer.LastName, DateOfBirth = mea.tblMeetSwimmerCheckIn.tblSwimmerSeason.tblSwimmer.DateOfBirth, GenderId = mea.tblMeetSwimmerCheckIn.tblSwimmerSeason.tblSwimmer.GenderID, RaceStrokeId = mea.tblMeetEvent.RaceStrokeID, AgeGroupId = mea.tblMeetEvent.AgeGroupID, AgeDesc = mea.tblMeetEvent.tblAgeGroup.AgeDesc, RaceLengthId = mea.tblMeetEvent.tblAgeGroup.RaceLengthID}; foreach (var databaseRecord in q) { individualEvent = new IndividualEvent(); individualEvent.RecordId = "D0"; individualEvent.OrganizationCode = "1"; individualEvent.SwimmerName = databaseRecord.FirstName + " " + databaseRecord.LastName; individualEvent.USSwimmingNumber = "??????"; individualEvent.SwimmerBirthDate = CreateFormattedDate(databaseRecord.DateOfBirth); individualEvent.SwimmerAgeOrClass = "??"; individualEvent.SwimmerSex = CreateFormattedGender(databaseRecord.GenderId); individualEvent.EventSex = CreateFormattedGender(databaseRecord.GenderId); individualEvent.EventDistance = CreateFormattedEventDistance(databaseRecord.RaceLengthId); individualEvent.EventStroke = CreateFormattedEventStroke(databaseRecord.RaceStrokeId); individualEvent.EventAge = databaseRecord.AgeDesc; individualEvent.SeedTime = "99.99"; individualEvent.EventCourseCode = "Y"; individualEvents.Add(individualEvent); } } return individualEvents; }

An example of the Individual Helper functions that does the actual translation:

public string CreateFormattedEventDistance(int raceLengthId) { switch (raceLengthId) { case 1: return "15"; case 2: return "25"; case 3: return "50"; case 4: return "100"; default: return "0"; } }

After hooking up all of my translations, I was ready to create an output file.   All I had to do was write this

static void WriteToFile() { string fileName = @"C:\Users\Public\HHTest01.SD3"; MeetSetupFactory factory = new MeetSetupFactory(); Collection<string> collection = factory.CreateMeetSetUp(72); System.IO.File.WriteAllLines(fileName, collection); }

and because of polymorphism, the output came out perfectly:

 

A01V3      01                              Tff LLC.            1.0X      James Dixon         9193884228  02212011                                              
B11        Olive Chapel                  Highcroft Pool                                                                  0720201007202010            Y         
C11              Highcroft Hurricanes          HHST            100 Highcroft Drive                         Cary                NC27519     USA                 
D01        Sloan Dixon                 040420Dix*Sl    040420020708MM25  2    7-8         99.99   Y                                                              
D01        Sloan Dixon                 040420Dix*Sl    040420020708MM25  3    7-8         99.99   Y                                                             

Guest Lecture At The University of Michigan

I had the honor of presenting at the University Of Michigan’s School Of Public Health/Information HMP605 Health Information Technology class yesterday.

photo (4)

Contrary to the picture – there were actually students in the class – about 30 divided between the School Of Information and the School Of Public Health.

I talked about topics that I wished I knew on my first day on the job as a software developer.  I also talked about what potential project managers and IT decision makers should know about software development to maximize their company’s (and own) success.  I also fielded some questions from the students.  I found the students bright, articulate, and very eager.  Hopefully, they will hit the ground running come May when they start in their new jobs.

 

No code this week – I was too busy preparing for the presentation.   See you next Tuesday.

How do you know when a text box has an auto-complete?

I was working with TFS Build when I ran into this screen:

image

I went to Windows Explorer to get the entire path to CTRL-C/V into the text box when I realized that the text box had an auto-complete feature.  This saved me the time to switch between Windows Explorer and TFS, which was good.  However, outside of the documentation, how would I know that the text box has auto-complete turned on?  Drop Down text boxes have a down arrow by convention, multi-lists have a vertical bar, but there is nothing for auto-complete.  When Google introduced auto-complete, it expected a search phrase so they did not include any visual clue:

image

I am wondering if there should be some kind of visual clue that the text box auto-completes?  Perhaps a red-arrow in the far-right of the box? Anyone have any ideas?

Carpool Project: Part #13

I am closer to the end of the development cycle than the beginning and I have run into a new problem. I created a method that Inserts new practices in the PracticeFactory. When I test it against the server, I get the following error

1 Test method Com.Tff.Carpool.Domain.Tests.PracticeFactoryTest.InsertPracticeTest threw exception: 2 System.Data.UpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: The conversion of a datetime2 data type to a datetime data type resulted in an out-of-range value. 3 The statement has been terminated. 4  

I searched MSDN/StackOverflow and I came up with the EF needing to be 2005, not 2008 (here) I switched it and got the same problem. This solution doesn’t make sense to me – b/c the data server is 2008. I then decided to look at the SQL that EF is generating to see if I can find an error in that code. There is a method called ToTraceString() that I can use to inspect the SQL generated – the trick is to locate what object the method belongs to – since it is not part of ObjectContext. The MSDN example here is not much help – I wonder if EF does not expose the method? In addition, I can’t set up tracing on the remote server – it is hosted on WinHost. I then found this post which solved the problem – it is just a feature gap in EF.

Once I had this code up and running, I looked at the results:

1 insert [dbo].[Carpool_Practice]([PracticeDate], [PracticeStartTime], [PracticeEndTime], [DrylandIndicator]) 2 values (@0, @1, @2, @3) 3 select [PracticeId] 4 from [dbo].[Carpool_Practice] 5  where @@ROWCOUNT > 0 and [PracticeId] = scope_identity() 6 @0 = 9/13/2010 7:17:53 AM 7 @1 = 1/1/0001 12:00:00 AM 8 @2 = 1/1/2010 7:00:00 PM 9 @3 = True 10  

And here is the bug:

1 private static void MapPractice_Practice(Carpool_Practice practiceToInsert, Practice practice) 2 { 3 practiceToInsert.DrylandIndicator = practice.DryLandIndicator; 4 practiceToInsert.PracticeDate = practice.Date; 5 practiceToInsert.PracticeEndTime = practice.EndTime; 6 practiceToInsert.PracticeStartTime = practiceToInsert.PracticeStartTime; 7 } 8  

I changed it to this:

1 practiceToInsert.PracticeStartTime = practice.StartTime;

And it ran. I was assigning the EF value to itself.

<Sound of me slapping my forehead>

Carpool Project: Part #11

I wanted to have a list of all of the swimmers NOT associated with a carpool. I got a list of all swimmers and then a list of all swimmers in carpool. I first started doing some nested For..Each and quickly realized I was doing something wrong. I went to 101 LINQ Samples and got a much better implementation (sample #52). I whipped this code:

1 public static List<Swimmer> GetNonCarpooledSwimmers(int carpoolId) 2 { 3 List<Swimmer> allSwimmers = SwimmerFactory.GetAllSwimmers(); 4 List<Swimmer> carpooledSwimmers = CarpoolFactory.GetCarpool(carpoolId).Swimmers; 5 return allSwimmers.Except(carpooledSwimmers).ToList<Swimmer>(); 6 } 7  

and ran a test:

Carpool67

Red! Dangnabbit.

I went to the definition of Except and realized that I did not implement a custom GetHashCode or Equals() for Swimmer. I popped this code into my Swimmer class:

1 2 public override int GetHashCode() 3 { 4 return this.Id; 5 } 6 7 public override bool Equals(object obj) 8 { 9 Swimmer other = obj as Swimmer; 10 if (other == null) 11 { 12 return base.Equals(obj); 13 } 14 else 15 { 16 if (other.Id == this.Id) 17 { 18 return true; 19 } 20 else 21 { 22 return false; 23 } 24 25 } 26 } 27  

 

And things ran like a champ…

Unsafe At Any Speed

What I wrote in Visual Studio 2010:   

    

 public unsafe void waitForAttachment(int milliseconds)
        {
            
if (this.managerPhidget)
            {
                
throw new PhidgetException(PhidgetException.GetErrorDesc(11), 11);
            }
            
int code = Phidget21Imports.CPhidget_waitForAttachment(this.phidgetDeviceHandle, milliseconds);
            
if (code != 0)
            {
                
throw new PhidgetException(code);
            }
            
while (!this.initialized)
            {
                
Thread.Sleep(10);
            }
        }

 

 What Reflector came up with:

public void waitForAttachment(int milliseconds)

{

    if (this.managerPhidget)

    {

        throw new PhidgetException(PhidgetException.GetErrorDesc(11), 11);

    }

    int code = Phidget21Imports.CPhidget_waitForAttachment(this.phidgetDeviceHandle, milliseconds);

    if (code != 0)

    {

        throw new PhidgetException(code);

    }

    while (!this.initialized)

    {

        Thread.Sleep(10);

    }

Note how Reflector dropped the “unsafe” keyword.

 

Also, I learned:

·         Static Methods cannot be in an interface

·         Internal Methods cannot be in an interface

·         I dropped Abstract b/c the code had references to its own instance

Voice Activated Toaster

I have played around with both the Speech API and the Phidget API over the last 5-7 years or so.  For the speech API, I created a home automation system to use the speech engine to control a house’s sound system, a cook’s recipe system, and to read the news and weather to a causal listener.  If patents weren’t $10,000, I would have sent something in – my neighbor in Alexandria worked at the Patent Office and thought it had a good chance to get approved, but I digress.  For the Phidget API, I did something similar to Brian Peek’s animated light show on Coding-4-Fun’s where I synched my Christmas’s lights to music.

I recently got back into both APIs to build a voice-activated toaster.  I plan to expand the project to include mocking of these external dependencies (the Phidget board/Toaster and the speech engine). 

To build the connection to the toaster, I used the Phidget 0/0/4 Interface kit.  I then wired it up like Brian did:

To handle the voice input, I used a cheap wireless microphone system from radio shack and hooked it into my microphone port. 

I used an old toaster that was hanging around my attic.

 I then slapped up a quick console application.  The application creates a connection to the Phidget board, starts up a speech recognition engine and listens for the word “Toast”.  Once recognized, the Phidget channel opens and the toaster is activated.  Once the word “Stop” is heard, the toaster is deactivated.

Here is the console output:

and here is the toaster in action:

 

I recognize that the code is not ready for prime time (heck, does not even have error handling), but I wanted to get a working skeleton down before throwing in my unit tests and mocking framework.  There will be more on that next week.  Here are the 80 lines of code that I needed to write to get it working:

 

namespace Com.Tff.VoiceActivatedToaster

{

    class Program

    {

        private static InterfaceKit interfaceKit = null;

 

        static void Main(string[] args)

        {

            Console.WriteLine("Starting");

            CreateSpeechRecognitionEngine();

            CreatePhigitInterface();

            Console.ReadKey();

        }

 

        private static void CreateSpeechRecognitionEngine()

        {

            SpeechRecognitionEngine speechRecognitionEngine = new SpeechRecognitionEngine();

           

            Choices choices = new Choices();

            choices.Add("Toast");

            choices.Add("Stop");

            Grammar grammar = new Grammar(choices);

 

            speechRecognitionEngine.LoadGrammar(grammar);

            speechRecognitionEngine.SetInputToDefaultAudioDevice();

            speechRecognitionEngine.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(speechRecognitionEngine_SpeechRecognized);

            speechRecognitionEngine.RecognizeAsync(RecognizeMode.Multiple);

            Console.WriteLine("Computer is listening");

        }

 

        static void speechRecognitionEngine_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)

        {

            Console.WriteLine("{0} was recognized with {1} confidence", e.Result.Text, e.Result.Confidence.ToString());

            if (e.Result.Text == "Toast")

            {

                interfaceKit.outputs[0] = true;

            }

 

            if (e.Result.Text == "Stop")

            {

                interfaceKit.outputs[0] = false;

            }

        }

 

        private static void CreatePhigitInterface()

        {

            interfaceKit = new InterfaceKit();

            interfaceKit.open();

 

        }

    }

}

 

 

POCOs

I started working through the POCO Template for Entity Framework found here.  I got through the exercise and have a pretty good idea of the what (if not the why) of POCOs.  I ran into a couple of gotchas:

 

If you spell

string inputFile = @"..\POCOTTemplateWalkthrough\Blogging.edmx";

wrong

You get this error:

Error             1                     Running transformation: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. —> System.IO.FileNotFoundException: Unable to locate file

   at Microsoft.VisualStudio.TextTemplating.VSHost.TextTemplatingService.ResolvePath(String path)

   at Microsoft.VisualStudio.TextTemplating.VSHost.TextTemplatingService.ResolvePath(String path)

 

Once I got to step #9, I ran it and it worked.  I then created a new Console app to be my User Tier, changed the project type of  POCOTemplateWalkthrough to a Class Library, and moved the Program.cs file to the UI.

To my surprise, it did not compile:

I then had to add a reference to Entities (I thought my UI could be Entity-unaware?) to get it compile and run.  It compiled but when I ran it, I got the following error:

{"Violation of PRIMARY KEY constraint ‘PK_People’. Cannot insert duplicate key in object ‘dbo.People’.\r\nThe statement has been terminated."}

I then deleted the 1st record in the data table table to get it to work

 

I ran it again and it worked:

Since I did not specify the ID, it is defaulting to 0 (the tutorial needs to be fixed some).  I then looked at the database table and confirmed that there was no identity key:

I changed it to identity and updated the Entity Framework and POW!

Of course, another way to do it is to add this line of code:

person.ID = 2;

 

But who wants to keep track of Primary Keys on the Data Layer? That is what identity keys are for.  I am a fan of surrogate keys, not a fan of composite keys.