Showing posts with label EF4. Show all posts
Showing posts with label EF4. Show all posts

Monday, May 16, 2011

NBuilder Extensions–US Address Randomizer– Make EF Code First Drop Database Less Painful

Have you used Entity Framework 4.1 Code First?  Specifically, have you used EF Code First with ASP.NET MVC 3 and MvcScaffolding?  If you have, you’ve felt the pain associated with adding properties to your model class, re-generating the code, and the framework requiring dropping of your database table and all the data that the table contains.  I’ve heard that Microsoft is planning of a solution to this, but in the meantime, we’re stuck with it…

A couple months ago, a colleague of mine recommended that I try out NBuilder.

NBuilder makes the aforementioned EF Code First pains suck less.  Less meaning that the pains still suck, but they are more tolerable.  If you’re not familiar with NBuilder, the NBuilder Website describes NBuilder as the following:

“Through a fluent, extensible interface, NBuilder allows you to rapidly create test data, automatically assigning values to properties and public fields that are of type of the built in .NET data types (e.g. ints and strings). NBuilder allows you to override for properties you are interested in using lambda expressions.”

That is exactly what it is.  But, how does it help EF Code First dropping tables requirement suck less?  Well, you can create an database initializer class that derives from DropCreateDatabaseIfModelChanges<T>, where T is your DbContext class, that contains a Seed method that will insert data into your data tables.  More on this later…  If you’re lost and/or not familiar with any of these terms (with the exception of NBuilder), I recommend that you check out Steve Sanderson’s Mix 11 cast: Scaffolding – ASP.NET, NuGet, Entity Framework Code First and More.

BTW, NBuilder is available via NuGet.

NBuilder contains facilities to randomly generate all kinds of data and data types including primitive types, phone numbers, date and time, first name, last name, addresses, etc... NBuilder also contains address randomizers; however, the randomizer supporting US addresses is not quite as useful as the randomizer for UK addresses.  Therefore, I created a class to generate more useful US addresses.  Below is a class snippet for this US address randomizer:

UsAddressRandomizer

using System.Collections.Generic;
using FizzWare.NBuilder.Generators;

namespace FizzWare.NBuilder
{
    public class UsAddressRandomizer
    {
        private static readonly IRandomGenerator Generator = new RandomGenerator();

        #region Data Generation
        private static readonly List<UsAddressFake> States =
            new List<UsAddressFake>
                {
                    new UsAddressFake { StateName = "Alaska", StateCode = "AK", ZipRangeBegin = 99500, ZipRangeEnd = 99999},
                    new UsAddressFake { StateName = "Alabama", StateCode = "AL", ZipRangeBegin = 35000, ZipRangeEnd = 36999},
                    new UsAddressFake { StateName = "Arkansas", StateCode = "AR", ZipRangeBegin = 71600, ZipRangeEnd = 72999},
                    new UsAddressFake { StateName = "Arizona", StateCode = "AZ", ZipRangeBegin = 85000, ZipRangeEnd = 86599},
                    new UsAddressFake { StateName = "California", StateCode = "CA", ZipRangeBegin = 90000, ZipRangeEnd = 96699},
                    new UsAddressFake { StateName = "Colorado", StateCode = "CO", ZipRangeBegin = 80000, ZipRangeEnd = 81699},
                    new UsAddressFake { StateName = "Connecticut", StateCode = "CT", ZipRangeBegin = 6000, ZipRangeEnd = 6999},
                    new UsAddressFake { StateName = "Delaware", StateCode = "DE", ZipRangeBegin = 19700, ZipRangeEnd = 19999},
                    new UsAddressFake { StateName = "Florida", StateCode = "FL", ZipRangeBegin = 32000, ZipRangeEnd = 34999},
                    new UsAddressFake { StateName = "Georgia", StateCode = "GA", ZipRangeBegin = 30000, ZipRangeEnd = 31999},
                    new UsAddressFake { StateName = "Hawaii", StateCode = "HI", ZipRangeBegin = 96700, ZipRangeEnd = 96899},
                    new UsAddressFake { StateName = "Iowa", StateCode = "IA", ZipRangeBegin = 50000, ZipRangeEnd = 52899},
                    new UsAddressFake { StateName = "Idaho", StateCode = "ID", ZipRangeBegin = 83200, ZipRangeEnd = 83899},
                    new UsAddressFake { StateName = "Illinois", StateCode = "IL", ZipRangeBegin = 60000, ZipRangeEnd = 62999},
                    new UsAddressFake { StateName = "Indiana", StateCode = "IN", ZipRangeBegin = 46000, ZipRangeEnd = 47999},
                    new UsAddressFake { StateName = "Kansas", StateCode = "KS", ZipRangeBegin = 66000, ZipRangeEnd = 67999},
                    new UsAddressFake { StateName = "Kentucky", StateCode = "KY", ZipRangeBegin = 40000, ZipRangeEnd = 42799},
                    new UsAddressFake { StateName = "Louisiana", StateCode = "LA", ZipRangeBegin = 70000, ZipRangeEnd = 71499},
                    new UsAddressFake { StateName = "Massachusetts", StateCode = "MA", ZipRangeBegin = 1000, ZipRangeEnd = 2799},
                    new UsAddressFake { StateName = "Maryland", StateCode = "MD", ZipRangeBegin = 20600, ZipRangeEnd = 21999},
                    new UsAddressFake { StateName = "Maine", StateCode = "ME", ZipRangeBegin = 3900, ZipRangeEnd = 4999},
                    new UsAddressFake { StateName = "Michigan", StateCode = "MI", ZipRangeBegin = 48000, ZipRangeEnd = 49999},
                    new UsAddressFake { StateName = "Minnesota", StateCode = "MN", ZipRangeBegin = 55000, ZipRangeEnd = 56799},
                    new UsAddressFake { StateName = "Missouri", StateCode = "MO", ZipRangeBegin = 63000, ZipRangeEnd = 65899},
                    new UsAddressFake { StateName = "Mississippi", StateCode = "MS", ZipRangeBegin = 38600, ZipRangeEnd = 39799},
                    new UsAddressFake { StateName = "Montana", StateCode = "MT", ZipRangeBegin = 59000, ZipRangeEnd = 59999},
                    new UsAddressFake { StateName = "North Carolina", StateCode = "NC", ZipRangeBegin = 26900, ZipRangeEnd = 28999},
                    new UsAddressFake { StateName = "North Dakota", StateCode = "ND", ZipRangeBegin = 58000, ZipRangeEnd = 58899},
                    new UsAddressFake { StateName = "Nebraska", StateCode = "NE", ZipRangeBegin = 68000, ZipRangeEnd = 69399},
                    new UsAddressFake { StateName = "New Hampshire", StateCode = "NH", ZipRangeBegin = 3000, ZipRangeEnd = 3999},
                    new UsAddressFake { StateName = "New Jersey", StateCode = "NJ", ZipRangeBegin = 7000, ZipRangeEnd = 8999},
                    new UsAddressFake { StateName = "New Mexico", StateCode = "NM", ZipRangeBegin = 87000, ZipRangeEnd = 88499},
                    new UsAddressFake { StateName = "Nevada", StateCode = "NV", ZipRangeBegin = 88900, ZipRangeEnd = 89899},
                    new UsAddressFake { StateName = "New York", StateCode = "NY", ZipRangeBegin = 500, ZipRangeEnd = 6399},
                    new UsAddressFake { StateName = "Ohio", StateCode = "OH", ZipRangeBegin = 43000, ZipRangeEnd = 45999},
                    new UsAddressFake { StateName = "Oklahoma", StateCode = "OK", ZipRangeBegin = 73000, ZipRangeEnd = 74999},
                    new UsAddressFake { StateName = "Oregon", StateCode = "OR", ZipRangeBegin = 97000, ZipRangeEnd = 97999},
                    new UsAddressFake { StateName = "Pennsylvania", StateCode = "PA", ZipRangeBegin = 15000, ZipRangeEnd = 19699},
                    new UsAddressFake { StateName = "Rhode Island", StateCode = "RI", ZipRangeBegin = 2800, ZipRangeEnd = 2999},
                    new UsAddressFake { StateName = "South Carolina", StateCode = "SC", ZipRangeBegin = 29000, ZipRangeEnd = 29999},
                    new UsAddressFake { StateName = "South Dakota", StateCode = "SD", ZipRangeBegin = 57000, ZipRangeEnd = 57799},
                    new UsAddressFake { StateName = "Tennessee", StateCode = "TN", ZipRangeBegin = 37000, ZipRangeEnd = 38599},
                    new UsAddressFake { StateName = "Texas", StateCode = "TX", ZipRangeBegin = 75000, ZipRangeEnd = 79999},
                    new UsAddressFake { StateName = "Utah", StateCode = "UT", ZipRangeBegin = 84000, ZipRangeEnd = 84799},
                    new UsAddressFake { StateName = "Vermont", StateCode = "VT", ZipRangeBegin = 5000, ZipRangeEnd = 5999},
                    new UsAddressFake { StateName = "Virginia", StateCode = "VA", ZipRangeBegin = 22000, ZipRangeEnd = 24699},
                    new UsAddressFake { StateName = "Washington", StateCode = "WA", ZipRangeBegin = 98000, ZipRangeEnd = 99499},
                    new UsAddressFake { StateName = "Wisconsin", StateCode = "WI", ZipRangeBegin = 53000, ZipRangeEnd = 54999},
                    new UsAddressFake { StateName = "West Virginia", StateCode = "WV", ZipRangeBegin = 24700, ZipRangeEnd = 26899},
                    new UsAddressFake { StateName = "Wyoming", StateCode = "WY", ZipRangeBegin = 82000, ZipRangeEnd = 83199}
                };

        private static readonly List<string> Cities =
            new List<string>
                {
                    "Abington",
                    "Acton",
                    "Acushnet",
                    "Adams",
                    "Agawam",
                    "Alford",
                    "Amesbury",
                    "Amherst",
                    "Andover",
                    "Aquinnah",
                    "Arlington",
                    "Ashburnham",
                    "Ashby",
                    "Ashfield",
                    "Ashland",
                    "Athol",
                    "Attleboro",
                    "Auburn",
                    "Avon",
                    "Ayer",
                    "Barnstable",
                    "Barre",
                    "Becket",
                    "Bedford",
                    "Belchertown",
                    "Bellingham",
                    "Belmont",
                    "Berkley",
                    "Berlin",
                    "Bernardston",
                    "Beverly",
                    "Billerica",
                    "Blackstone",
                    "Blandford",
                    "Bolton",
                    "Boston",
                    "Bourne",
                    "Boxborough",
                    "Boxford",
                    "Boylston",
                    "Braintree",
                    "Brewster",
                    "Bridgewater",
                    "Brimfield",
                    "Brockton",
                    "Brookfield",
                    "Brookline",
                    "Buckland",
                    "Burlington",
                    "Cambridge",
                    "Canton",
                    "Carlisle",
                    "Carver",
                    "Charlemont",
                    "Charlton",
                    "Chatham",
                    "Chelmsford",
                    "Chelsea",
                    "Cheshire",
                    "Chester",
                    "Chesterfield",
                    "Chicopee",
                    "Chilmark",
                    "Clarksburg",
                    "Clinton",
                    "Cohasset",
                    "Colrain",
                    "Concord",
                    "Conway",
                    "Cummington",
                    "Dalton",
                    "Danvers",
                    "Dartmouth",
                    "Dedham",
                    "Deerfield",
                    "Dennis",
                    "Dighton",
                    "Douglas",
                    "Dover",
                    "Dracut",
                    "Dudley",
                    "Dunstable",
                    "Duxbury",
                    "East Bridgewater",
                    "East Brookfield",
                    "East Longmeadow",
                    "Eastham",
                    "Easthampton",
                    "Easton",
                    "Edgartown",
                    "Egremont",
                    "Erving",
                    "Essex",
                    "Everett",
                    "Fairhaven",
                    "Fall River",
                    "Falmouth",
                    "Fitchburg",
                    "Florida",
                    "Foxborough",
                    "Framingham",
                    "Franklin",
                    "Freetown",
                    "Gardner",
                    "Georgetown",
                    "Gill",
                    "Gloucester",
                    "Goshen",
                    "Gosnold",
                    "Grafton",
                    "Granby",
                    "Granville",
                    "Great Barrington",
                    "Greenfield",
                    "Groton",
                    "Groveland",
                    "Hadley",
                    "Halifax",
                    "Hamilton",
                    "Hampden",
                    "Hancock",
                    "Hanover",
                    "Hanson",
                    "Hardwick",
                    "Harvard",
                    "Harwich",
                    "Hatfield",
                    "Haverhill",
                    "Hawley",
                    "Heath",
                    "Hingham",
                    "Hinsdale",
                    "Holbrook",
                    "Holden",
                    "Holland",
                    "Holliston",
                    "Holyoke",
                    "Hopedale",
                    "Hopkinton",
                    "Hubbardston",
                    "Hudson",
                    "Hull",
                    "Huntington",
                    "Ipswich",
                    "Kingston",
                    "Lakeville",
                    "Lancaster",
                    "Lanesborough",
                    "Lawrence",
                    "Lee",
                    "Leicester",
                    "Lenox",
                    "Leominster",
                    "Leverett",
                    "Lexington",
                    "Leyden",
                    "Lincoln",
                    "Littleton",
                    "Longmeadow",
                    "Lowell",
                    "Ludlow",
                    "Lunenburg",
                    "Lynn",
                    "Lynnfield",
                    "Malden",
                    "Manchester-by-the-Sea",
                    "Mansfield",
                    "Marblehead",
                    "Marion",
                    "Marlborough",
                    "Marshfield",
                    "Mashpee",
                    "Mattapoisett",
                    "Maynard",
                    "Medfield",
                    "Medford",
                    "Medway",
                    "Melrose",
                    "Mendon",
                    "Merrimac",
                    "Methuen",
                    "Middleborough",
                    "Middlefield",
                    "Middleton",
                    "Milford",
                    "Millbury",
                    "Millis",
                    "Millville",
                    "Milton",
                    "Monroe",
                    "Monson",
                    "Montague",
                    "Monterey",
                    "Montgomery",
                    "Mount Washington",
                    "Nahant",
                    "Nantucket",
                    "Natick",
                    "Needham",
                    "New Ashford",
                    "New Bedford",
                    "New Braintree",
                    "New Marlborough",
                    "New Salem",
                    "Newbury",
                    "Newburyport",
                    "Newton",
                    "Norfolk",
                    "North Adams",
                    "North Andover",
                    "North Attleborough",
                    "North Brookfield",
                    "North Reading",
                    "Northampton",
                    "Northborough",
                    "Northbridge",
                    "Northfield",
                    "Norton",
                    "Norwell",
                    "Norwood",
                    "Oak Bluffs",
                    "Oakham",
                    "Orange",
                    "Orleans",
                    "Otis",
                    "Oxford",
                    "Palmer",
                    "Paxton",
                    "Peabody",
                    "Pelham",
                    "Pembroke",
                    "Pepperell",
                    "Peru",
                    "Petersham",
                    "Phillipston",
                    "Pittsfield",
                    "Plainfield",
                    "Plainville",
                    "Plymouth",
                    "Plympton",
                    "Princeton",
                    "Provincetown",
                    "Quincy",
                    "Randolph",
                    "Raynham",
                    "Reading",
                    "Rehoboth",
                    "Revere",
                    "Richmond",
                    "Rochester",
                    "Rockland",
                    "Rockport",
                    "Rowe",
                    "Rowley",
                    "Royalston",
                    "Russell",
                    "Rutland",
                    "Salem",
                    "Salisbury",
                    "Sandisfield",
                    "Sandwich",
                    "Saugus",
                    "Savoy",
                    "Scituate",
                    "Seekonk",
                    "Sharon",
                    "Sheffield",
                    "Shelburne",
                    "Sherborn",
                    "Shirley",
                    "Shrewsbury",
                    "Shutesbury",
                    "Somerset",
                    "Somerville",
                    "South Hadley",
                    "Southampton",
                    "Southborough",
                    "Southbridge",
                    "Southwick",
                    "Spencer",
                    "Springfield",
                    "Sterling",
                    "Stockbridge",
                    "Stoneham",
                    "Stoughton",
                    "Stow",
                    "Sturbridge",
                    "Sudbury",
                    "Sunderland",
                    "Sutton",
                    "Swampscott",
                    "Swansea",
                    "Taunton",
                    "Templeton",
                    "Tewksbury",
                    "Tisbury",
                    "Tolland",
                    "Topsfield",
                    "Townsend",
                    "Truro",
                    "Tyngsborough",
                    "Tyringham",
                    "Upton",
                    "Uxbridge",
                    "Wakefield",
                    "Wales",
                    "Walpole",
                    "Waltham",
                    "Ware",
                    "Wareham",
                    "Warren",
                    "Warwick",
                    "Washington",
                    "Watertown",
                    "Wayland",
                    "Webster",
                    "Wellesley",
                    "Wellfleet",
                    "Wendell",
                    "Wenham",
                    "West Boylston",
                    "West Bridgewater",
                    "West Brookfield",
                    "West Newbury",
                    "West Springfield",
                    "West Stockbridge",
                    "West Tisbury",
                    "Westborough",
                    "Westfield",
                    "Westford",
                    "Westhampton",
                    "Westminster",
                    "Weston",
                    "Westport",
                    "Westwood",
                    "Weymouth",
                    "Whately",
                    "Whitman",
                    "Wilbraham",
                    "Williamsburg",
                    "Williamstown",
                    "Wilmington",
                    "Winchendon",
                    "Winchester",
                    "Windsor",
                    "Winthrop",
                    "Woburn",
                    "Worcester",
                    "Worthington",
                    "Wrentham",
                    "Yarmouth"
                };

        private static readonly List<string> Streets =
            new List<string>
                {
                    "107th Street",
                    "10th Avenue",
                    "10th Street",
                    "11th Avenue",
                    "11th Street",
                    "12th Avenue",
                    "12th Street",
                    "137th Street",
                    "13th Street",
                    "14th Road",
                    "14th Street",
                    "17th Street",
                    "181st Street",
                    "18th Street",
                    "19th Street",
                    "1st Avenue",
                    "1st Street",
                    "23rd Street",
                    "25th Street",
                    "2nd Avenue",
                    "2nd Street",
                    "30th Avenue",
                    "31st Street",
                    "33rd Street",
                    "34th Avenue",
                    "35th Avenue",
                    "35th Street",
                    "36th Street",
                    "37th Avenue",
                    "39th Avenue",
                    "3rd Avenue",
                    "3rd Street",
                    "45th Avenue",
                    "47th Avenue",
                    "4th Avenue",
                    "4th Street",
                    "51st Avenue",
                    "52 Chambers Street",
                    "52nd Street",
                    "5th Avenue",
                    "5th Street",
                    "68th Street",
                    "6th Avenue",
                    "6th Street",
                    "76th Street",
                    "77th Street",
                    "78th Street",
                    "79th Street",
                    "7th Avenue",
                    "7th Avenue South",
                    "7th Street",
                    "80th Street",
                    "81st Street",
                    "82nd Street",
                    "83rd Street",
                    "84th Street",
                    "85th Street",
                    "86th Street",
                    "87th Street",
                    "88th Street",
                    "8th Avenue",
                    "8th Street",
                    "90th Avenue",
                    "90th Street",
                    "9th Avenue",
                    "9th Street",
                    "Abingdon Square",
                    "Adelphi Street",
                    "Albemarle Road",
                    "Albemarle Terrace",
                    "Alexander Avenue",
                    "Amboy Road",
                    "Amity Street",
                    "Amsterdam Avenue",
                    "Andrews Avenue",
                    "Argyle Road",
                    "Arthur Kill Road",
                    "Ashland Place",
                    "Astor Place",
                    "Atlantic Avenue",
                    "Available",
                    "Avenue A",
                    "Avenue Of Americas",
                    "Avenue Of The Americas",
                    "Avenue Z",
                    "Bainbridge Street",
                    "Baltic Street",
                    "Bank Street",
                    "Barclay Street",
                    "Barrow Street",
                    "Baxter Street",
                    "Beach 124th Street",
                    "Beach Street",
                    "Beaver Road",
                    "Beaver Street",
                    "Beck Street",
                    "Bedford Avenue",
                    "Bedford Street",
                    "Beekman Place",
                    "Beekman Street",
                    "Bergen Street",
                    "Berkeley Place",
                    "Bethune Street",
                    "Bicycle Racks",
                    "Bleecker Street",
                    "Bond Street",
                    "Boston Road",
                    "Botanical Garden",
                    "Bowery Street",
                    "Bowling Green",
                    "Bowne Street",
                    "Bridge Street",
                    "Brielle Avenue",
                    "Brighton Beach Avenue",
                    "Broad Street",
                    "Broadway",
                    "Brooklyn Heights",
                    "Broome Street",
                    "Buckingham Road",
                    "Bushwick Avenue",
                    "Cadman Plaza West",
                    "Calyer Street",
                    "Cambridge Place",
                    "Canal Street",
                    "Carlton Avenue",
                    "Carroll Gardens Historic Distr",
                    "Carroll Place",
                    "Carroll Street",
                    "Central  Park West",
                    "Central Avenue",
                    "Central Park  West",
                    "Central Park North",
                    "Central Park South",
                    "Central Park West",
                    "Centre Street",
                    "Chambers Street",
                    "Charles Street",
                    "Charlton Street",
                    "Chatham Square",
                    "Chauncey Street",
                    "Cheever Place",
                    "Chelsea Square Park",
                    "Christopher Street",
                    "Chruch Street",
                    "Church Avenue",
                    "Church Street",
                    "City College",
                    "City Hall",
                    "Clark Street",
                    "Classon Avenue",
                    "Clay Avenue",
                    "Clermont Avenue",
                    "Clifton Place",
                    "Clinton Avenue",
                    "Clinton Street",
                    "Clove Road",
                    "Coenties Slip",
                    "College Place",
                    "Columbia Heights",
                    "Columbia Place",
                    "Columbia Street",
                    "Columbus Avenue",
                    "Columbus Street",
                    "Commerce Street",
                    "Congress Street",
                    "Convent Avenue",
                    "Cooper Square",
                    "Cornelia Street",
                    "Cornell Cemetery",
                    "Court Place",
                    "Court Square",
                    "Court Street",
                    "Cranberry Street",
                    "Cropsey Avenue",
                    "Crosby Street",
                    "Croton Aqueduct",
                    "Cumberland Street",
                    "Dalny Road",
                    "Dawson Street",
                    "Dean Street",
                    "Decatur Street",
                    "Degraw Street",
                    "Dekalb Avenue",
                    "Ditmars Boulevard",
                    "Ditmas Avenue",
                    "Dorchester Avenue",
                    "Doris Freedman Plaza",
                    "Doughty Street",
                    "Dover Street",
                    "Downing Street",
                    "Drinking Fountain",
                    "Duane Street",
                    "Dyre Avenue",
                    "Eagle Street",
                    "East 103rd Street",
                    "East 104th Street",
                    "East 106th Street",
                    "East 10th Street",
                    "East 110th Street",
                    "East 11th Street",
                    "East 121st Street",
                    "East 125th Street",
                    "East 12th Street",
                    "East 136th Street",
                    "East 139th Street",
                    "East 13th Street",
                    "East 140th Street",
                    "East 141st Street",
                    "East 14th Street",
                    "East 151st Street",
                    "East 156th Street",
                    "East 15th Street",
                    "East 161st Street",
                    "East 166th Street",
                    "East 16th Street",
                    "East 179th Street",
                    "East 17th Street",
                    "East 17th Stret",
                    "East 18th Street",
                    "East 19th Street",
                    "East 20th Street",
                    "East 21st Street",
                    "East 22nd Street",
                    "East 23rd Street",
                    "East 24th Street",
                    "East 29th Street",
                    "East 32nd Street",
                    "East 34th Street",
                    "East 35th Street",
                    "East 36th Street",
                    "East 3rd Street",
                    "East 41st Street",
                    "East 42nd Street",
                    "East 43rd Street",
                    "East 44th Street",
                    "East 45th Street",
                    "East 46th Street",
                    "East 48th Street",
                    "East 49th Street",
                    "East 4th Street",
                    "East 50th Street",
                    "East 52nd Street",
                    "East 53rd Street",
                    "East 54th Street",
                    "East 55th Street",
                    "East 56th Street",
                    "East 57th Street",
                    "East 58th Street",
                    "East 59th Street",
                    "East 60th Street",
                    "East 61st Street",
                    "East 62nd Street",
                    "East 63rd Street",
                    "East 64th Street",
                    "East 65th Street",
                    "East 66th Street",
                    "East 67th Street",
                    "East 68th Street",
                    "East 69th Street",
                    "East 6th Street",
                    "East 70th Street",
                    "East 71st Street",
                    "East 72nd Street",
                    "East 73rd Street",
                    "East 74th Street",
                    "East 75th Street",
                    "East 76th Street",
                    "East 77th Street",
                    "East 78th Street",
                    "East 79th Street",
                    "East 7th Street",
                    "East 80th Street",
                    "East 81st Street",
                    "East 82nd Street",
                    "East 83rd Street",
                    "East 84th Street",
                    "East 85th Street",
                    "East 86th Street",
                    "East 87th Street",
                    "East 88th Street",
                    "East 89th Street",
                    "East 8th Street",
                    "East 90th Street",
                    "East 91st Street",
                    "East 92dnd Street",
                    "East 92nd Street",
                    "East 93rd Street",
                    "East 94th Street",
                    "East 95th Street",
                    "East 96th Street",
                    "East 9th Street",
                    "East Broadway",
                    "East End Avenue",
                    "East Fordham Road",
                    "East Tremont Avenue",
                    "Eastern Parkway",
                    "Edgecombe Avenue",
                    "Eldridge Street",
                    "Elizabeth Street",
                    "Elk Street",
                    "Emmons Avenue",
                    "Ericsson Place",
                    "Everit Street",
                    "Exchange Place",
                    "Faile Street",
                    "Federal Plaza",
                    "Fenimore Street",
                    "Fifth Avenue",
                    "Fillmore Street",
                    "Fiske Place",
                    "Flagg Court",
                    "Flagg Place",
                    "Flatbush Avenue",
                    "Flatbush Malls",
                    "Foley Square",
                    "Fordham University",
                    "Forest Avenue",
                    "Fort Greene Avenue",
                    "Fort Greene Place",
                    "Fort Totten Avenue",
                    "Fort Washington Avenue",
                    "Franklin Avenue",
                    "Franklin Street",
                    "Frederick Douglas Boulevard",
                    "Front Street",
                    "Fulton Ferry Streets",
                    "Fulton Fish Market",
                    "Fulton Landing",
                    "Fulton Street",
                    "Gansevoort Street",
                    "Garden Place",
                    "Garfield Place",
                    "Gates Avenue",
                    "Gateway Boulevard",
                    "Gay Street",
                    "Grace Court",
                    "Grace Court Alley",
                    "Grace Street",
                    "Gracie Mansion",
                    "Gramercy Park East",
                    "Gramercy Park North",
                    "Gramercy Park South",
                    "Gramercy Park West",
                    "Gramercy Place",
                    "Grand Army Plaza",
                    "Grand Avenue",
                    "Grand Central Terminal",
                    "Grand Concourse",
                    "Grand Street",
                    "Grant Street",
                    "Great Jones Street",
                    "Great Kills Road",
                    "Green Wood Cemetery",
                    "Greene Avenue",
                    "Greene Street",
                    "Greenpoint Avenue",
                    "Greenport Road",
                    "Greenwich Avenue",
                    "Greenwich Mews",
                    "Greenwich Street",
                    "Greenwich Village",
                    "Grove Court",
                    "Grove Street",
                    "Guernsey Street",
                    "Hall Street",
                    "Hamilton Avenue",
                    "Hamilton Place",
                    "Hamilton Terrace",
                    "Hanover Square",
                    "Hanson Place",
                    "Harrison Street",
                    "Heberton Avenue",
                    "Henderson Place",
                    "Henry Hudson Parkway",
                    "Henry Street",
                    "Heritage Trail",
                    "Heritage Trails",
                    "Hester Street",
                    "Hewitt Place",
                    "Hicks Street",
                    "High Bridge Aqueduct",
                    "Horatio Street",
                    "Howard Street",
                    "Hoyt Street",
                    "Hubert Street",
                    "Hudson Street",
                    "Hunts Lane",
                    "Hunts Lane Alley",
                    "Hydrants",
                    "Hylan Boulevard",
                    "Independence Avenue",
                    "Irving Place",
                    "Jackson Avenue",
                    "Jackson Street",
                    "Jamaica Avenue",
                    "James Street",
                    "Jane Street",
                    "Jay Street",
                    "Jefferson Avenue",
                    "Jerome Avenue",
                    "John Street",
                    "Jones Street",
                    "Joralemon Street",
                    "Jumel Terrace",
                    "Kane Street",
                    "Kelly Street",
                    "Kenmore Terrace",
                    "Kent Street",
                    "King Street",
                    "Kings Highway",
                    "Kingsbridge Terrace",
                    "Lafayette Avenue",
                    "Lafayette Street",
                    "Laguardia Airport",
                    "Laight Street",
                    "Lefferts Avenue",
                    "Lefferts Homestead",
                    "Lefferts Place",
                    "Lefferts Road",
                    "Lenox Avenue",
                    "Leonard Street",
                    "Leroy Street",
                    "Lewis Avenue",
                    "Lexington Avenue",
                    "Liberty Street",
                    "Lighting",
                    "Lincoln Avenue",
                    "Lincoln Place",
                    "Lincoln Road",
                    "Linwood Street",
                    "Lispenard Street",
                    "Little Bay",
                    "Little Neck Parkway",
                    "Little West 12th Street",
                    "Livingston Street",
                    "Lorillard Snuff Mill",
                    "Lorimer Street",
                    "Louis Street",
                    "Love Lane",
                    "Macdonough Street",
                    "Macdougal Alley",
                    "Macdougal Street",
                    "Macon Street",
                    "Madison Avenue",
                    "Madison Street",
                    "Maiden Lane",
                    "Main Street",
                    "Malcolm X Boulevard",
                    "Manhattan Avenue",
                    "Maple Street",
                    "Marcus Garvey Boulevard",
                    "Marcus Garvey Park",
                    "Marcy Avenue",
                    "Marlborough Road",
                    "Maujer Street",
                    "Mcdonald Avenue",
                    "Mercer Street",
                    "Middagh Street",
                    "Midwood Street",
                    "Milligan Place",
                    "Milton Avenue",
                    "Milton Street",
                    "Mitchell Place",
                    "Monroe Place",
                    "Montague Street",
                    "Montague Terrace",
                    "Montgomery Place",
                    "Morris Avenue",
                    "Morris Park Avenue",
                    "Morton Street",
                    "Mott Street",
                    "Mount Morris Park West",
                    "Mulry Square",
                    "Murray Street",
                    "Narrows Avenue",
                    "Nassau Street",
                    "Nevins Street",
                    "New Dorp Lane",
                    "New Lots Avenue",
                    "Newkirk Avenue",
                    "Nixon Avenue",
                    "Noble Street",
                    "Norfolk Street",
                    "Norman Avenue",
                    "North Moore Street",
                    "Northern Boulevard",
                    "Nostrand Avenue",
                    "Nycta Subway Entrance",
                    "Oak Street",
                    "Ocean Avenue",
                    "Ocean Parkway",
                    "Ogden Avenue",
                    "Old Fulton Street",
                    "Old Slip",
                    "Oliver Street",
                    "Orange Street",
                    "Pacific Street",
                    "Park Avenue",
                    "Park Avenue South",
                    "Park Place",
                    "Park Row",
                    "Park Row North",
                    "Patchin Place",
                    "Pearl Street",
                    "Peck Slip",
                    "Pedestrian Ramps",
                    "Pell Mansion",
                    "Perry Street",
                    "Pierrepont Place",
                    "Pierrepont Street",
                    "Pike Street",
                    "Pineapple Street",
                    "Plaque",
                    "Plaques",
                    "Plaza Street",
                    "Plaza Street West",
                    "Polhemus Place",
                    "Polhemus Street",
                    "Pomander Walk",
                    "Poplar Street",
                    "Powells Cove Boulevard",
                    "President Street",
                    "Prince Street",
                    "Prospect Park West",
                    "Putnam Avenue",
                    "Quincy Street",
                    "Reade Street",
                    "Recycling Cans",
                    "Remsen Avenue",
                    "Remsen Street",
                    "Revere Place",
                    "Richmond Hill Road",
                    "Richmond Road",
                    "Richmond Street",
                    "Richmond Terrace",
                    "Riverdale Avenue",
                    "Riverside Drive",
                    "Riverside Drive West",
                    "Riverside Park",
                    "Rockefeller Center",
                    "Rockefeller Plaza",
                    "Rockland Avenue",
                    "Rogers Avenue",
                    "Roosevelt Avenue",
                    "Roosevelt Island",
                    "Rufus King Manor",
                    "Rugby Road",
                    "Rutherford Place",
                    "Rutland Road",
                    "Ryerson Street",
                    "Sailors' Snug Harbor",
                    "Schermerhorn Street",
                    "Sedgwick Avenue",
                    "Sequine Avenue",
                    "Sheridan Square",
                    "Shore Road",
                    "Sidney Place",
                    "Simpson Street",
                    "Smith Street",
                    "Sniffen Court",
                    "Snug Harbor",
                    "Snug Harbor Cultural Center",
                    "Snyder Avenue",
                    "South 9th Street",
                    "South Elliott Place",
                    "South Oxford Street",
                    "South Portland Avenue",
                    "South Portland Street",
                    "South Street",
                    "South Street Seaport",
                    "South William Street",
                    "Southern Boulevard",
                    "Spring Street",
                    "St. Alban's Place",
                    "St. Andrew's Plaza",
                    "St. Ann's Avenue",
                    "St. Felix Street",
                    "St. James Place",
                    "St. Johns Place",
                    "St. John's Place",
                    "St. Lukes Place",
                    "St. Luke's Place",
                    "St. Mark Avenue",
                    "St. Marks Avenue",
                    "St. Marks Place",
                    "St. Mark's Place",
                    "St. Nicholas Avenue",
                    "St. Nicholas Terrace",
                    "St. Patrick's Place",
                    "St. Paul's Avenue",
                    "State Street",
                    "Sterling Place",
                    "Sterling Street",
                    "Stone Street",
                    "Stratford Road",
                    "Street Signs",
                    "Strong Place",
                    "Stuyvesant Avenue",
                    "Stuyvesant Square",
                    "Stuyvesant Street",
                    "Sullivan Street",
                    "Sutphin Boulevard",
                    "Sutton Place",
                    "Sycamore Avenue",
                    "Sylvan Terrace",
                    "Thomas Street",
                    "Thompson Street",
                    "Throop Avenue",
                    "Times Square",
                    "Tompkins Avenue",
                    "Tompkins Place",
                    "Trinity Place",
                    "Tudor City",
                    "Tudor City Place",
                    "Union Hall Street",
                    "Union Square West",
                    "Union Street",
                    "University Place",
                    "Van Cortlandt Mansion",
                    "Vandam Street",
                    "Vanderbilt Avenue",
                    "Varick Street",
                    "Verandah Place",
                    "Verdi Square",
                    "Vernon Boulevard",
                    "Vesey Street",
                    "Vestry Street",
                    "Village Road South",
                    "Walker Street",
                    "Wall Street",
                    "Warren Place",
                    "Warren Street",
                    "Warsoff Place",
                    "Washington Avenue",
                    "Washington Mews",
                    "Washington Place",
                    "Washington Square North",
                    "Washington Square South",
                    "Washington Square West",
                    "Washington Street",
                    "Water Street",
                    "Watts Street",
                    "Wave Hill",
                    "Waverly Avenue",
                    "Waverly Place",
                    "Webster Avenue",
                    "Weirfield Street",
                    "West 101st Street",
                    "West 102nd Street",
                    "West 105th Street",
                    "West 106th Street",
                    "West 107th Street",
                    "West 108th Street",
                    "West 109th Street",
                    "West 10th Street",
                    "West 114th Street",
                    "West 115th Street",
                    "West 119th Street",
                    "West 11th Street",
                    "West 120th Street",
                    "West 121st Street",
                    "West 122nd Street",
                    "West 123rd Street",
                    "West 125th Street",
                    "West 126th Street",
                    "West 127th Street",
                    "West 128th Street",
                    "West 129th Street",
                    "West 12th Street",
                    "West 130th Street",
                    "West 134th Street",
                    "West 135th Street",
                    "West 138th Street",
                    "West 139th Street",
                    "West 13th Street",
                    "West 140th Street",
                    "West 141st Street",
                    "West 142nd Street",
                    "West 143rd Street",
                    "West 144th Street",
                    "West 145th Street",
                    "West 148th Street",
                    "West 14th Street",
                    "West 150th Street",
                    "West 151st Street",
                    "West 155th Street",
                    "West 156th Street",
                    "West 160th Street",
                    "West 162nd Street",
                    "West 16th Street",
                    "West 17th Street",
                    "West 18th Street",
                    "West 19th Street",
                    "West 20th Street",
                    "West 21st Street",
                    "West 22nd Street",
                    "West 23rd Street",
                    "West 247th Street",
                    "West 249th Street",
                    "West 24th Street",
                    "West 252nd Street",
                    "West 25th Street",
                    "West 261st Street",
                    "West 26th Street",
                    "West 27th Street",
                    "West 29th Street",
                    "West 31st Street",
                    "West 33rd Street",
                    "West 34th Street",
                    "West 37th Street",
                    "West 3rd Street",
                    "West 40th Street",
                    "West 41st Street",
                    "West 42nd Street",
                    "West 43rd Street",
                    "West 44th Street",
                    "West 45th Street",
                    "West 46th Street",
                    "West 47th Street",
                    "West 48th Street",
                    "West 49th Street",
                    "West 4th Street",
                    "West 50th Street",
                    "West 51st Street",
                    "West 52nd Street",
                    "West 53rd Street",
                    "West 54th Street",
                    "West 55th Street",
                    "West 56th Street",
                    "West 57th Street",
                    "West 58th Street",
                    "West 59th Street",
                    "West 5th Street",
                    "West 61st Street",
                    "West 63rd Street",
                    "West 64th Street",
                    "West 65th Street",
                    "West 66th Street",
                    "West 67th Street",
                    "West 68th Street",
                    "West 69th Street",
                    "West 70th Street",
                    "West 71st Street",
                    "West 72nd Street",
                    "West 73rd Street",
                    "West 74th Street",
                    "West 75th Street",
                    "West 76th Street",
                    "West 77th Street",
                    "West 78th Street",
                    "West 79th Street",
                    "West 80th Street",
                    "West 81st Street",
                    "West 82nd Street",
                    "West 83rd Street",
                    "West 84th Street",
                    "West 85th Street",
                    "West 86th Street",
                    "West 87th Street",
                    "West 88th Street",
                    "West 89th Street",
                    "West 8lst Street",
                    "West 8th Street",
                    "West 90th Street",
                    "West 91st Street",
                    "West 92nd Street",
                    "West 93rd Street",
                    "West 94th Street",
                    "West 95th Street",
                    "West 96th Street",
                    "West 9th Street",
                    "West Broadway",
                    "West Drive",
                    "West End Avenue",
                    "West Houston Street",
                    "West Kingsbridge Road",
                    "West Street",
                    "Westervelt Avenue",
                    "Westminster Road",
                    "White Street",
                    "William Street",
                    "Willoughby Avenue",
                    "Willoughby Street",
                    "Willow Place",
                    "Willow Street",
                    "Wilson Avenue",
                    "Winant Place",
                    "Woodrow Road",
                    "Woodycrest Avenue",
                    "Wooster Street",
                    "Worth Street",
                    "Wyckoff Street",
                    "York Avenue"
                };
        #endregion Data Generation

        public static string Street()
        {
            return Streets[Generator.Next(0, Streets.Count - 1)];
        }

        public static string City()
        {
            return Cities[Generator.Next(0, Cities.Count - 1)];
        }

        public static string StateName()
        {
            return States[Generator.Next(0, States.Count - 1)].StateName;
        }

        public static string StateCode()
        {
            return States[Generator.Next(0, States.Count - 1)].StateCode;
        }

        public static string Zip()
        {
            return Zip(false);
        }

        public static string Zip(bool withExtension)
        {
            var address = States[Generator.Next(0, States.Count - 1)];
            return Zip(withExtension, address.ZipRangeBegin, address.ZipRangeEnd);
        }

        private static string Zip(bool withExtension, int zipRangeBegin, int zipRangeEnd)
        {
            var zip = Generator.Next(zipRangeBegin, zipRangeEnd);
            var pre = string.Format("{0:d5}", zip);

            if (!withExtension) return pre;

            var post = Zip(false);
            return string.Format("{0}-{1}", pre, post.Substring(0, 4));
        }

        public static string FullAddress()
        {
            return FullAddress(false);
        }

        public static string FullAddress(bool withExtension)
        {
            var address = States[Generator.Next(0, States.Count - 1)];

            return string.Format("{0} {1}, {2}, {3} {4}",
                Generator.Next(1, 10000),
                Street(),
                City(),
                address.StateName,
                 Zip(withExtension, address.ZipRangeBegin, address.ZipRangeEnd));
        }

        public static string PhoneNumber()
        {
            return GetRandom.Usa.PhoneNumber();
        }

        public static string SocialSecurityNumber()
        {
            return GetRandom.Usa.SocialSecurityNumber();
        }

        internal class UsAddressFake
        {
            internal string StateName { get; set; }
            internal string StateCode { get; set; }
            internal int ZipRangeBegin { get; set; }
            internal int ZipRangeEnd { get; set; }
        }
    }
}
You can use this class in your project, or create a separate project and add the class to the project and import the project reference into you project containing your DbContext class.

Let’s say that you’ve created a Visual Studio solution with an ASP.NET MVC 3 application, EF Code First and using MvcScaffolding – similar to Steve Sanderson’s Mix 11 cast: Scaffolding – ASP.NET, NuGet, Entity Framework Code First and More.  Your MVC 3 project contains the following two Model classes and DbContext classs:

using System;
using System.Collections.Generic;

namespace MvcCodeFirstSqlCompact.Models
{
    public class Dinner
    {
        public int DinnerId { get; set; }
        public string Title { get; set; }
        public DateTime EventDate { get; set; }
        public string Address { get; set; }
        public string HostedBy { get; set; }
        public string UrlLink { get; set; }

        public virtual ICollection<Rsvp> Rsvps { get; set; }
    }
}

namespace MvcCodeFirstSqlCompact.Models
{
    public class Rsvp
    {
        public int RsvpId { get; set; }
        public string AttendeeEmail { get; set; }

        public int DinnerId { get; set; }
        public virtual Dinner Dinner { get; set; }
    }
}

namespace MvcCodeFirstSqlCompact.Models
{
    public class MvcCodeFirstSqlCompactContext : DbContext
    {
        public MvcCodeFirstSqlCompactContext()
        {
            Database.SetInitializer(new MvcCodeFirstSqlCompactInitializer());
        }

        public DbSet<MvcCodeFirstSqlCompact.Models.Dinner> Dinners { get; set; }

        public DbSet<MvcCodeFirstSqlCompact.Models.Rsvp> Rsvps { get; set; }
    }
}
Notice how the DbContext constructor sets the initializer to MvcCodeFirstSqlCompactInitializer.  This is the class that will insert data into your data source once a change in made to one of your model classes and requires database tables to be dropped.  The following snippet is the code for the MvcCodeFirstSqlCompactInitializer:

using System;
using System.Data.Entity;
using FizzWare.NBuilder;
using FizzWare.NBuilder.Generators;

namespace MvcCodeFirstSqlCompact.Models
{
    public class MvcCodeFirstSqlCompactInitializer : DropCreateDatabaseIfModelChanges<MvcCodeFirstSqlCompactContext>
    {
        protected override void Seed(MvcCodeFirstSqlCompactContext context)
        {
            var uniqueGenerator = new UniqueRandomGenerator();
            var generator = new RandomGenerator();

            var dinners = Builder<Dinner>.CreateListOfSize(10).WhereAll()
                .Have(d => d.Title = string.Format("{0} {1} Dinner", uniqueGenerator.Next(0, 100), GetRandom.UK.County()))
                .And(d => d.Address = UsAddressRandomizer.FullAddress(true))
                .And(d => d.HostedBy = string.Format("{0} {1}", GetRandom.FirstName(), GetRandom.LastName()))
                .And(d => d.EventDate = uniqueGenerator.Next(new DateTime(2010, 1, 1), new DateTime(2011, 5, 4)))
                .And(d => d.UrlLink = "http://" + GetRandom.Url())
                .Build();

            foreach (var dinner in dinners)
                context.Dinners.Add(dinner);

            var rsvps = Builder<Rsvp>.CreateListOfSize(300).WhereAll()
                .Have(d => d.AttendeeEmail = GetRandom.Email())
                .And(d => d.Dinner = dinners[generator.Next(1, 10)])
                .Build();

            foreach (var rsvp in rsvps)
                context.Rsvps.Add(rsvp);
        }
    }
}
Notice how this class derives from DropCreateDatabaseIfModelChanges<T>, where T is your DbContext class?  This class will execute the code in the overridden the Seed method when EF Code First needs to create OR recreate the data source.  In the above scenario, the Seed method uses the NBuilder and UsAddressRandomizer facilities to generate data and insert the data into your data tables. 

No more manual data insertions into your database once EF Code First creates/recreates the database.  Not as sweet as EF Code First combined with MvcScaffolding, but pretty sweet nonetheless?

All pains aside, I’m really impressed with EF Code First and liking it more and more everyday.  That said, I hope this post and NBuilder helps your avoid some of the pain associated with EF Code First.

Again, if you are unfamiliar with any of the previous concepts and technologies, I highly recommend that you take a look at Steve Sanderson’s Mix 11 cast - Scaffolding – ASP.NET, NuGet, Entity Framework Code First and More, his blog series -  Scaffold your ASP.NET MVC 3 project with the MvcScaffolding package, and explore the usefulness of NBuilder.

Thanks for reading…

Tuesday, March 15, 2011

Another Entity Framework 4 Repository & Unit of Work Solution–Intro and Part 4: ASP.NET MVC 3 Project

This is Part 4 in a series of posts that walk through the process of implementing a solution that separates concerns into specific behaviors using the Entity Framework 4 and the Repository and Unit of Work Patterns.

Below is the series outline; again, this is Part 4.
Now on to Part 4… Open up the Chinook solution in Visual Studio. Let’s do a little solution organization.  Create the following three solution folders by right-clicking the solution file, selecting ‘Add,’ and then selecting ‘New Solution Folder.’ image
  • Core
  • Infrastructure
  • Web
Place the Chinook.Core project into the Core Solution Folder and place the other two projects (Chinook.Data.EF and Chinook.Infrastructure) into the Infrastructure Solution Folder.  The Web Solution Folder will contain our MVC Web application project.  Let’s do that now… Right-click the Web Solution Folder.  Click 'Add’ –> ‘New Project…’ image Next, create an ASP.NET MVC 3 Web Application and name is ‘Chinook.Web’ and click ‘OK.’ image On the next screen, select ‘Internet Application,’ the ‘Razor’ View engine, and click ‘OK’ image Right-click the new ‘Chinook.Web’ Application Project and select ‘Set As Startup Project.’  The solution structure should now look similar to the following: image Add the following References to the ‘Chinook.Web’ Project and then build the solution. image In the description of this post, it states that we are going to use StructureMpa as our DI container.  We are going to get StructureMap via NuGet.  Assuming you have NuGet installed, select the Chinook.Web project, open the ‘Package Manager Console,’ and type the following command:
PM> Install-Package StructureMap
This will install StructureMap and register any assemblies with the Chinook.Web project.  Once the NuGet command is executed, the NuGet Package Manager Console should echo the following: image Go ahead and build the solution. Next, add the the new StructureMap reference to both the Chinook.Data.EF and Chinook.Infrastructure projects and rebuild the solution. Again, this series assumes that you have all the necessary tools (NuGet, POCO templates, etc…) installed with Visual Studio and that you are somewhat familiar with StructureMap. Now, remember the two files (EFRepositoryRegistry.cs.txt and ServicesRegistry.cs.txt) that the T4 templates generated for us in the previous post?  We are going to use those files to create our StructureMap registries.  The best way to do this is to create two new cs files in the respective projects, copy the code from the generated file, and paste it into these new code files.  I understand this is not idea (copy, paste, etc…); however, I didn’t want to limit our solution to StructureMap only, so we’ll just have to deal with the awkwardness for now.  So, create the following files and replace all the code in the new code file with the code in the associated generated file.
  • EFRepositoryRegistry.cs – in the Chinook.Data.EF project
    • EFRepositoryRegistry.cs.txt – generated file
  • ServicesRegistry.cs – in the Services directory within the Chinook.Implementation project
    • ServicesRegistry.cs.txt – generated file
Go ahead and build the solution again. Next, we are going to register our repositories, unit of work, and other dependencies (created earlier in a previous post) with StructureMap in our Chinook.Web project.  To do this, we are going to use ASP.NET MVC 3 IDependencyResolver – you can read about IDependencyResolver here and read the API docs here. Create a ‘Bootstrap’ directory in the Chinook.Web project and create the following two empty code/class files:
  • StructureMapContainerSetup.cs – make this class static
  • StructureMapDependencyResolver.cs
Now we are going to register the Registries created earlier in these ‘bootstrap’ files.  Since this series of posts is walk through on the process of setting up a solution for separation of concerns and not on the theory of such topics, the exercise of explaining the StructureMap registration is beyond the scope of this series.  Populate these newly created code files with the following content:
StructureMapDependencyResolver
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using StructureMap;

namespace Chinook.Web.Bootstrap
{
    public class StructureMapDependencyResolver : IDependencyResolver
    {
        private readonly IContainer _container;

        public StructureMapDependencyResolver(IContainer container)
        {
            _container = container;
        }

        #region Implementation of IDependencyResolver

        /// <summary>
        /// Resolves singly registered services that support arbitrary object creation.
        /// </summary>
        /// <returns>
        /// The requested service or object.
        /// </returns>
        /// <param name="serviceType">The type of the requested service or object.</param>
        public object GetService(Type serviceType)
        {
            var instance = _container.TryGetInstance(serviceType);

            if ((instance == null) && !serviceType.IsAbstract)
            {
                _container.Configure(c => c.AddType(serviceType, serviceType));
                instance = _container.TryGetInstance(serviceType);
            }
            return instance;
        }

        /// <summary>
        /// Resolves multiply registered services.
        /// </summary>
        /// <returns>
        /// The requested services.
        /// </returns>
        /// <param name="serviceType">The type of the requested services.</param>
        public IEnumerable<object> GetServices(Type serviceType)
        {
            return _container.GetAllInstances(serviceType).Cast<object>();
        }

        #endregion
    }
}
StructureMapContainerSetup
using System.Web.Mvc;
using Chinook.Data.EF;
using Chinook.Infrastructure.Services;
using StructureMap;

namespace Chinook.Web.Bootstrap
{
    public static class StructureMapContainerSetup
    {
        public static void Setup()
        {
            IContainer container = new Container(
                x =>
                    {
                        x.AddRegistry(new EFRepositoryRegistry());
                        x.AddRegistry(new ServicesRegistry());
                    }
                );

            DependencyResolver.SetResolver(new StructureMapDependencyResolver(container));
        }
    }
}
Now we are going to invoke the StructureMap registration bootstrapping code from the Application_Start method of the Global.asax.cs file.  Here’s the snippet:
protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    StructureMapContainerSetup.Setup();

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
}
Go ahead and build the solution again… We are now going to create a quick controller, view, and some supporting View Models that will give a simple example how to use all the code created in this series of posts.  For this part, go ahead and download the final solution.  Logically representing the code here will be difficult and would provide little value without context; therefore, download the final solution and review the code in the Chinook.Web project.  Here’s a quick list of the steps involved to generated the code samples:
  1. Create a ViewModel - AlbumGridItemViewModel.
  2. Create a IViewModelBuilder/ViewModelBuilder – IAlbumGridItemViewModelBuilder/AlbumGridItemViewModelBuilder.
  3. Create a new Controller - AlbumController.
  4. Use constructor injection to inject the ViewModelBuilder into the Controller -  IAlbumGridItemViewModelBuilder into the AlbumController.
  5. Create a View to represent a list of ViewModel items – Index – this is only a list of items; however, the process remains the same for all types of views.
  6. Register the IViewModelBuilder/ViewModelBuilder with StructureMap – using a similar pattern as the other DI registrations – a StructureMap Registry.
The resulting list generated in the sample code is not designed for performance (e.g. no paging, sorting, etc..).  In production, this type of code can and should be refactored.  That said, the key points throughout this series are the patterns used to create a solution based on separation of concerns – including the Repository and Unit of Work patterns and using StructureMap as a Dependency Injection container.

Thanks for reading…

Another Entity Framework 4 Repository & Unit of Work Solution–Intro and Part 2: Creating the Repositories and Unit of Work (UoW)

This is Part 2 in a series of posts that walk through the process of implementing a solution that separates concerns into specific behaviors using the Entity Framework 4 and the Repository and Unit of Work Patterns.

Below is the series outline; again, this is Part 2.
Now on to Part 2… The following download contains some T4 templates that I’ve created and/or modified from other sources.  These T4 templates will build all the code necessary to create our Domain Models, Domain Model Metadata (e.g. Data Annotations), Repositories, Services, and Unit of Work all by pointing each related T4 to the EF data model (edmx) created in Part 1 of this series. T4 Templates Download. Go ahead and download the zip file and un-compress the contents into a directory directly under the solution root.  The solution’s root directory should look something like the following, where the T4_EF4_Repository directory is the directory that contains the uncompressed files from the download. p2Solutionlist00 Open up the T4_EF4_Repository directory.  The directory should contain a ‘Source’ directory and a single PowerShell file: image The ‘Source’ directory should contain six T4 template files (*.tt) image What are these files?  Well, the files with the *.tt extension are the T4 templates that will generate the code, while the single file with the *.ps1 extension is a PowerShell script.  The following briefly describes each file:
  • Domain.Poco.tt
    • This template generates the POCO (Domain) classes from your EF data model.
  • Domain.Poco.Metadata.tt
    • This template generates data annotations/metadata ‘buddy’ classes for the POCOs.
  • Repository.Interface.tt
    • This template generates all the associated Repository Interfaces/Contracts, including:
      • base IReadOnlyRepository and  IRepository Interfaces
      • IUnitOfWork Interface
      • I<POCO_ClassName>Repository Interface for each POCO class generated from you EF data model.
  • Repository.Implementation.EF.tt
    • This template generates the EF-related concrete class implementations defined by the IRepository Interfaces/Contracts.
  • Services.Interface.tt
    • This template generates a light-weight Service Interfaces/Contracts for each POCO class.
  • Services.Implementation.tt
    • This template generates the concrete class implementation defined by the Service Interfaces/Contracts.
  • prepareT4Templates.ps1
    • This is just a simple PowerShell script that contains project-specific settings to assist in generation T4 templates specific to the project – in our scenario, the Chinook application solution.
Open up the Chinook Visual Studio Solution. We should now have a Visual Studio Solution with thee Projects (Chinook.Core, Chinook.Data.EF, Chinook.Infrastructure) and a directory located at the solution root containing the T4 templates and single PowerShell file. Open up T4_EF4_Repository directory in Windows Explorer.  Right-click the PowerShell file and select ‘Edit’ from the context menu.  image This will open up the PowerShell editor and display the content of the PowerShell file.  As you can see, this is simple script that does a find/replace, creates a new directory, and creates new T4 templates that contain the replaced settings.
#*****************************************************************
#*****************************************************************
#*********** BEGIN Template Parameters ***************************
#*****************************************************************

# path to the project's edmx data model (entity framework data model)
$edmxFilePath = "..\..\Chinook.Data.Ef\Chinook.edmx"
# the namepace name where the solution's domain models live 
$domainModelNamespace = "Chinook.Core.Domain"
# the namespace name where the solution's services will live
$serviceInterfaceNamespace = "Chinook.Core.Services"
# the namespace name where the solution's repository will live
$repositoryInterfaceNamespace = "Chinook.Core.Repository"

#*****************************************************************
#*********** END Template Parameters *****************************
#*****************************************************************

function createDirectory($directory){
New-Item $directory -type directory -force    
}

function removeDestinationFile($file){
if(Test-Path $file){ Remove-Item $file }
}

function writeout($file){
$sourceFile = "Source/" + $file
$destinationDirectory = "Solution/"    
$destinationFile = $destinationDirectory + $file

createDirectory($destinationDirectory)    
removeDestinationFile($destinationFile)

(Get-Content $sourceFile) |
Foreach-Object {$_ -replace "\[\*\*EDMX_FILE_PATH\*\*\]", $edmxFilePath} | 
Foreach-Object {$_ -replace "\[\*\*DOMAIN_MODEL_NAMESPACE\*\*\]", $domainModelNamespace} |
Foreach-Object {$_ -replace "\[\*\*SERVICE_INTERFACE_NAMESPACE\*\*]", $serviceInterfaceNamespace} |
Foreach-Object {$_ -replace "\[\*\*REPOSITORY_INTERFACE_NAMESPACE\*\*\]", $repositoryInterfaceNamespace} |
Set-Content $destinationFile
}

$files = @("Domain.Poco.tt", "Domain.Poco.Metadata.tt", "Repository.Interface.tt", "Service.Interface.tt", "Repository.Implementation.EF.tt", "Service.Implementation.tt")

foreach($file in $files){
writeout($file)
}
As I mentioned above, the PowerShell file will generate T4 templates specific to your project.  If you followed along in Part 1, these setting variables are taken from the namespaces that we specified in the last step.  If you missed it, the following table duplicates our previous efforts:
Directory Namespace
Domain Chinook.Core.Domain
Repository Chinook.Core.Repository
Services Chinook.Core.Services
The following are the project-specific settings:
  • $edmxFilePath
    • relative path to the solution’s EF data model (edmx)

  • $domainModelNamespace
    • the namespace where the solution’s POCO’s live – see namespace table above
  • $serviceInterfaceNamespace
    • the namespace where the solution’s Service Interfaces/Contracts live – see namespace table above
  • $repositoryInterfaceNamespace
    • the namespace where the solution’s Repository Interfaces/Contracts live – see namespace table above
If you followed through this post's series, there is no need to change the aforementioned settings.  They are already set to the proper solution-specific settings.  If not, go ahead and change the necessary settings. You can run the PowerShell file within the editor of by right-clicking the PowerShell file and click ‘Run with PowerShell.’  However, since we already have the file open in the editor, we are going to use the editor. Click the ‘Run’ button on the editor’s toolbar: image If when running the PowerShell file you receive the following error, you do not have the proper permission to execute PowerShell scripts:
File C:\Chinook\T4_EF4_Repository\prepareT4Templates.ps1 cannot be loaded. The file C:\Chinook\T4_EF4_Repository\prepareT4Templates.ps1 is not digitally signed. The script will not execute on the system. Please see "get-help about_signing" for more details..
You have a couple choices to get around this, but the easiest is to set the PowerShell execution policy to ‘unrestricted’ using the following PowerShell command (* you must be running PowerShell as an Administrator).  Go ahead and run this command in the PowerShell console in the bottom pane of the PowerShell editor:
Set-ExecutionPolicy UnRestricted
Accept the ‘Execution Policy Change’ dialog message – the dialog only appears if you are using the editor.  If you are using the non-editor PowerShell console, this ‘Execution Policy Change’ message will only echo to the console. Sorry about that little hiccup.  If you’re not comfortable with setting the execution policy to 'unrestricted,’ you get reverse the policy back to ‘restricted’ once you’re done generating the necessary T4 templates by using the following PowerShell command:
Set-ExecutionPolicy Restricted
For more PowerShell documentation, check out MSDN. Close the PowerShell editor. Okay, back to the tutorial…  Once you execute the PowerShell script, the T4_EF4_Repository directory will now contain a new ‘Solution’ sub-directory and will contain six T4 templates with the project-specific settings defined earlier.  These are the templates that we will be using in our application. image image Still with me?  I hope so.  I know – it’s a bit long the first time, but it’s really pretty simple and will be worth the effort.  Hang in there… Next, if you haven’t already done so, open up the Chinook Visual Studio Solution.  We are now going to add the POCO generator to the EF Data Model.  If you don’t have the ADO.NET POCO Entity Generator template installed, you will need to add it via the Visual Studio Extension Manager from the Visual Studio Gallery.

Adding the POCO Template

  • Open up the Chinook.edmx file so the EF data model is visible in the designer (this is located in the Chinook.Data.EF project)
  • Right-click on an empty area of the EF data model canvas and select ‘Add Code Generation Item…’
p2addcodegen
  • This will bring up the ‘Add new Item Dialog,’ in which you will choose the ADO.NET POCO Entity Generator template (via the Installed Templates –> Code node)
p2addpoco
  • Set the ‘Name’ of the ADO.NET POCO Entity Generator item to ‘Poco.tt’
  • Save the EF data model (edmx file) and build the Chinook.Data.EF project.
  • Delete the Poco.tt file from the Chinook.Data.EF project
    • ** DO NOT delete the Poco.Context.tt file. 

Add the T4 Templates to the Solution

We are now going to add the T4 templates that we generated earlier.
Project Directory T4 Template (Solution directory)
Chinook.Core Domain Domain.Poco.tt
Chinook.Core Domain Domain.Poco.Metadata.tt
Chinook.Core Repository Repository.Interface.tt
Chinook.Core Services Service.Interface.tt
Chinook.Data.EF * add using Project node * Repository.Implementation.EF.tt
Chinook.Infrastructure Services Service.Implementation.tt
For each one of the following directories in the list above, add the associated T4 template in listed order by right-clicking the respective directory, clicking ‘Add / Existing Item…’, navigating to the T4_EF4_Repository/Solution directory (in the root of the solution) and selecting the associated T4 template.  A couple of notes…
  • You may need to use the ‘All File(*.*)’ filter on the ‘Add Existing Item’ dialog.
  • Ensure that you select the proper T4 templates  (e.g. use the ‘Solution’ directory and NOT the ‘Source’ directory)
image image

Build the Solution and Resolve Dependencies

Now, go ahead and build the solution and resolve any dependencies that appear in the Error List.  You will get errors on the ‘ObjectContext’ derived class (ChinookEntities in our scenario).  To resolve these errors, you will need to add a reference to the Domain namespace where the POCOs classes live (we identified this earlier in the ‘namespace’ table).  In our scenario, just add the following using statement to the ‘ChinookEntities’ class…
using Chinook.Core.Domain;
Build the solution again.  All the dependencies should now be resolved and the solution should build with no errors. In summary, we walked through the process of implementing a solution that separates concerns into specific behaviors using the Entity Framework 4 and the Repository and Unit of Work Patterns using T4 templates to generate the code using our EF data model

In the next post in this series, we will review a few of the generated class/interfaces that the T4 code generation templates created.

Thanks for reading…