<|start_filename|>ChristopherDemos/MusicStore/Views/Artists/Details.cshtml<|end_filename|>
﻿@model MusicStore.Models.Artist

@{
    ViewBag.Title = "Details";
}

<h2>Details</h2>

<div>
    <h4>Artist</h4>
    <hr />
    <dl class="dl-horizontal">
        <dt>
            @Html.DisplayNameFor(model => model.Name)
        </dt>

        <dd>
            @Html.DisplayFor(model => model.Name)
        </dd>

    </dl>
</div>
<h2>Albums</h2>
<ul>
	@foreach (var album in Model.Albums) {
		<li>@album.Title</li>
	}
</ul>
<p>
    @Html.ActionLink("Edit", "Edit", new { id = Model.ArtistID }) |
    @Html.ActionLink("Back to List", "Index")
</p>


<|start_filename|>ChristopherDemos/MusicStore/Models/Repositories/Repository.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MusicStore.Models.Repositories
{
	public class Repository<T> : IDisposable where T : class
	{
		private bool disposed = false;
		private MusicStoreDataContext context = null;

		protected DbSet<T> DbSet
		{
			get; set; 
		}

		public Repository()
		{
			context = new MusicStoreDataContext();
			DbSet = context.Set<T>();
		}

		public Repository(MusicStoreDataContext context)
		{
			this.context = context;
		}
		public List<T> GetAll()
		{
			return DbSet.ToList();
		}

		public T Get(int id)
		{
			return DbSet.Find(id);
		}

		public void Add(T entity)
		{
			DbSet.Add(entity);
		}

		public virtual void Update(T entity)
		{
			context.Entry<T>(entity).State = EntityState.Modified;
		}

		public void Delete(int id)
		{
			DbSet.Remove(DbSet.Find(id));
		}

		public void SaveChanges()
		{
			context.SaveChanges();
		}

		public void Dispose()
		{
			if(!disposed) {
				context.Dispose();
				disposed = true;
			}
		}
	}
}


<|start_filename|>ChristopherDemos/MusicStore/Controllers/ArtistsController.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.Data.Entity.Core;
using System.Linq;
using System.Transactions;
using System.Web;
using System.Web.Mvc;
using MusicStore.Models;
using MusicStore.Models.Repositories;

namespace MusicStore.Controllers
{
    public class ArtistsController : Controller
    {
        //MusicStoreDataContext context = new MusicStoreDataContext();
		ArtistRepository repository = new ArtistRepository();
		
		public ActionResult Details(int id)
		{
			Artist artist = repository.Get(id);
			if (artist == null) {
				return HttpNotFound();
			} else {
				return View(artist);
			}
		}

		// GET: Artists
        public ActionResult Index()
        {
			return View(repository.GetAll());
        }

		public ActionResult Create()
		{
			return View();
		}

		[HttpPost()]
		public ActionResult Create(Artist artist)
		{
			if(!ModelState.IsValid) return View(artist);
			
			repository.Add(artist);
			repository.SaveChanges();
			return RedirectToAction("Index");
		}

		public ActionResult Edit(int id)
		{
			var artist = repository.Get(id);
			if(artist == null) return HttpNotFound();
			else return View(artist);
		}

		[HttpPost()]
		public ActionResult Edit(Artist artist)
		{
			if (!ModelState.IsValid) return View(artist);

			try {
				using (TransactionScope scope = new TransactionScope()) {
					repository.Update(artist);
					repository.SaveChanges();
					scope.Complete();
				} 
				return RedirectToAction("Index");
			} catch (System.Data.Entity.Infrastructure.DbUpdateConcurrencyException) {
				ViewBag.Message = "Sorry, that didn't work!<br />Adam beat you to the punch";
				return View(artist);
			}
		}

		protected override void Dispose(bool disposing)
		{
			repository.Dispose();
			base.Dispose(disposing);
		}
    }
}

<|start_filename|>ChristopherDemos/MusicStore/Models/Repositories/ArtistRepository.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MusicStore.Models.Repositories
{
	public class ArtistRepository : Repository<Artist>
	{
		public List<Artist> GetByName(String name)
		{
			return DbSet.Where(a => a.Name.Contains(name)).ToList();
		}

		public override void Update(Artist entity)
		{
			base.Update(entity);
			SaveChanges();
			entity.Version++;
			base.Update(entity);
			SaveChanges();
		}

		public List<SoloArtist> GetSoloArtists()
		{
			return DbSet.OfType<SoloArtist>().ToList();
		}
	}
}


<|start_filename|>ChristopherDemos/MusicStore/Models/MusicStoreDataContextInitializer.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MusicStore.Models
{
	public class MusicStoreDataContextInitializer : DropCreateDatabaseAlways<MusicStoreDataContext>
	{
		protected override void Seed(MusicStoreDataContext context)
		{
			Artist artist = new Artist() { Name = "<NAME>"};
			context.Artists.Add(artist);

			context.Albums.Add(new Album() { Artist = artist, Title = "First Album" });
			context.Albums.Add(new Album() { Artist = artist, Title = "Second Album" });

			context.Albums.Add(new Album() {
				Artist = context.Artists.Add(new Artist() {Name = "<NAME>"}),
				Title = "Third Album"
			});

			context.Artists.Add(new SoloArtist() { Name = "Solo Artist", Instrument = "Piano" });

			context.SaveChanges();
		}
	}
}


<|start_filename|>ChristopherDemos/MusicStore/Models/Artist.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MusicStore.Models
{
	public class Artist
	{
		public int ArtistID { get; set; }

		[Required()]
		[StringLength(100, MinimumLength = 2)]
		public string Name { get; set; }

		//[Timestamp()]
		//public byte[] RowVersion { get; set; }

		[ConcurrencyCheck()]
		public int Version { get; set; }

		public virtual List<Album> Albums { get; set; }
		public virtual ArtistDetails ArtistDetails { get; set; }
		
	}
}


<|start_filename|>ChristopherDemos/MusicStore/ViewModels/AlbumCreateViewModel.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MusicStore.ViewModels
{
	public class AlbumCreateViewModel
	{
		public string AlbumTitle { get; set; }
		public string ArtistName { get; set; }
	}
}


<|start_filename|>ChristopherDemos/MusicStore/Models/ArtistDetails.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MusicStore.Models
{
	public class ArtistDetails
	{
		[Key()]
		[ForeignKey("Artist")]
		public int ArtistID { get; set; }
		public string Bio { get; set; }
		public virtual Artist Artist { get; set; }
	}
}


<|start_filename|>AdamDemos/ConcurrencyDetectionAndUserChoice/ConcurrencyDetectionAndUserChoice/Album.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;

namespace ConcurrencyDetectionAndUserChoice
{
    public class Album
    {
        public int AlbumId { get; set; }
        public string Title { get; set; }
        public decimal Price { get; set; }
        
        [Timestamp]
        public byte[] Timestamp { get; set; }
    }
}

<|start_filename|>AdamDemos/HandleConcurrencyExceptionFilter.cs<|end_filename|>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Data.Entity.Infrastructure;
using System.Reflection;


/// Code from <NAME>
/// adamtuliper.com @AdamTuliper (follow me on twitter!)
/// <EMAIL>
/// github.com/adamtuliper
/// Use this code as you wish, retain credit if possible. Enjoy!
/// ** Read all the below notes **

/// This attribute attempts to intercept DbUpdateConcurrencyException to write out original/new values
/// to the screen for the user to review.
/// It assumes the following:
/// 1. There is a [Timestamp] attribute on an entity framework model property
/// 2. The only differences that we care about from the posted data to the record currently in the database are 
/// only the model state field. We do not have access to a model at this point, as an exception was raised so there was no
/// return View(model) that we have a model to process from.
/// As such, we have to look at the fields in the modelstate and try to find matching fields on the entity and then display the differences.

/// This may not work in all cases of view models, etc. Test in your enviroment
/// Ensure you add this action filter in /App_Start/FilterConfig.cs
/// Also note that if you come across an exception in your controller from concurrency
/// the method execution will end. If you load data after that point that your controller requires
/// then you will need to ensure you catch that exception, load your data, and then throw; to continue
/// bubbling up to action filter (not throw ex as that rethrows a new exception)

/// This class will look at your model to get the property names. It will then check your
/// Entities current values vs. db values for these property names.
/// </summary>
public class HandleConcurrencyExceptionFilter : FilterAttribute, IExceptionFilter //ActionFilterAttribute
{
    private PropertyMatchingMode _propertyMatchingMode;
    /// <summary>
    /// This defines when the concurrencyexception happens, 
    /// </summary>
    public enum PropertyMatchingMode
    {
        /// <summary>
        /// Uses only the field names in the model to check against the entity. This option is best when you are using 
        /// View Models with limited fields as opposed to an entity that has many fields. The ViewModel (or model) field names will
        /// be used to check current posted values vs. db values on the entity itself.
        /// </summary>
        UseViewModelNamesToCheckEntity = 0,
        /// <summary>
        /// Use any non-matching value fields on the entity (except timestamp fields) to add errors to the ModelState.
        /// </summary>
        UseEntityFieldsOnly = 1,
        /// <summary>
        /// Tells the filter to not attempt to add field differences to the model state.
        /// This means the end user will not see the specifics of which fields caused issues
        /// </summary>
        DontDisplayFieldClashes = 2
    }

    /// <summary>
    /// The main method, called by the mvc runtime when an exception has occured.
    /// This must be added as a global filter, or as an attribute on a class or action method.
    /// </summary>
    /// <param name="filterContext"></param>
    public void OnException(ExceptionContext filterContext)
    {
        if (!filterContext.ExceptionHandled && filterContext.Exception is DbUpdateConcurrencyException)
        {
            //Get original and current entity values
            DbUpdateConcurrencyException ex = (DbUpdateConcurrencyException)filterContext.Exception;
            var entry = ex.Entries.Single();
            //problems with ef4.1/4.2 here because of context/model in different projects.
            //var databaseValues = entry.CurrentValues.Clone().ToObject();
            //var clientValues = entry.Entity;
            //So - if using EF 4.1/4.2 you may use this workaround
            var clientValues = entry.CurrentValues.Clone().ToObject();
            entry.Reload();
            var databaseValues = entry.CurrentValues.ToObject();

            List<string> propertyNames;

            filterContext.Controller.ViewData.ModelState.AddModelError(string.Empty, "The record you attempted to edit "
                    + "was modified by another user after you got the original value. The "
                    + "edit operation was canceled and the current values in the database "
                    + "have been displayed. If you still want to edit this record, click "
                    + "the Save button again to cause your changes to be the current saved values.");
            PropertyInfo[] entityFromDbProperties = databaseValues.GetType().GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);

            //We need to know where to get our property names from - an EF Entity or a view model
            //We default to using the passed model values (which may work for some entities as well)
            if (_propertyMatchingMode == PropertyMatchingMode.UseViewModelNamesToCheckEntity)
            {
                //We dont have access to the view model here on an exception. Get the field names from modelstate:
                propertyNames = filterContext.Controller.ViewData.ModelState.Keys.ToList();
            }
            else if (_propertyMatchingMode == PropertyMatchingMode.UseEntityFieldsOnly)
            {
                //We are using an Entity framework entity. In this case, just get the fields names from the Entity
                propertyNames = databaseValues.GetType().GetProperties(BindingFlags.Public).Select(o => o.Name).ToList();
            }
            else
            {
                filterContext.ExceptionHandled = true;
                UpdateTimestampField(filterContext, entityFromDbProperties, databaseValues);
                filterContext.Result = new ViewResult() { ViewData = filterContext.Controller.ViewData };
                return;
            }



            UpdateTimestampField(filterContext, entityFromDbProperties, databaseValues);

            //Get all public properties of the entity that have names matching those in our modelstate.
            foreach (var propertyInfo in entityFromDbProperties)
            {

                //If this value is not in the ModelState values, don't compare it as we don't want
                //to attempt to emit model errors for fields that don't exist.

                //Compare db value to the current value from the entity we posted.

                if (propertyNames.Contains(propertyInfo.Name))
                {
                    if (propertyInfo.GetValue(databaseValues, null) != propertyInfo.GetValue(clientValues, null))
                    {
                        var currentValue = propertyInfo.GetValue(databaseValues, null);
                        if (currentValue == null || string.IsNullOrEmpty(currentValue.ToString()))
                        {
                            currentValue = "Empty";
                        }

                        filterContext.Controller.ViewData.ModelState.AddModelError(propertyInfo.Name, "Current value: "
                             + currentValue);
                    }
                }

                //TODO: hmm.... how can we only check values applicable to the model/modelstate rather than the entity we saved?
                //The problem here is we may only have a few fields used in the viewmodel, but many in the entity
                //so we could have a problem here with that. Need to resolve in those cases
            }

            filterContext.ExceptionHandled = true;

            filterContext.Result = new ViewResult() { ViewData = filterContext.Controller.ViewData };
        }
    }

    public HandleConcurrencyExceptionFilter()
    {
        _propertyMatchingMode = PropertyMatchingMode.UseViewModelNamesToCheckEntity;
    }

    /// <summary>
    /// You can override the default behavior 
    /// </summary>
    public HandleConcurrencyExceptionFilter(PropertyMatchingMode propertyMatchingMode)
    {
        _propertyMatchingMode = propertyMatchingMode;
    }


    /// <summary>
    /// Searches the database loaded entity values for a field that has a [Timestamp] attribute.
    /// It then writes a string version of ther byte[] timestamp out to modelstate, assuming 
    /// we have a timestamp field on the page that caused the concurrency exception.
    /// </summary>
    /// <param name="filterContext"></param>
    /// <param name="entityFromDbProperties"></param>
    /// <param name="databaseValues"></param>
    private void UpdateTimestampField(ExceptionContext filterContext, PropertyInfo[] entityFromDbProperties, object databaseValues)
    {
        foreach (var propertyInfo in entityFromDbProperties)
        {
            var attributes = propertyInfo.GetCustomAttributesData();

            //If this is a timestamp field, we need to set the current value.
            foreach (CustomAttributeData attr in attributes)
            {
                if (typeof(System.ComponentModel.DataAnnotations.TimestampAttribute).IsAssignableFrom(attr.Constructor.DeclaringType))
                {
                    //This currently works only with byte[] timestamps. You can use dates as timestamps, but support is not provided here.
                    byte[] timestampValue = (byte[])propertyInfo.GetValue(databaseValues, null);
                    //we've found the timestamp. Add it to the model.
                    filterContext.Controller.ViewData.ModelState.Add(propertyInfo.Name, new ModelState());
                    filterContext.Controller.ViewData.ModelState.SetModelValue(propertyInfo.Name,
                        new ValueProviderResult(Convert.ToBase64String(timestampValue), Convert.ToBase64String(timestampValue), null));
                    break;
                }
            }
        }
    }

}


<|start_filename|>ChristopherDemos/MusicStore/Models/MusicStoreDataContext.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MusicStore.Models
{
	public class MusicStoreDataContext : DbContext
	{
		public DbSet<Artist> Artists { get; set; }
		public DbSet<Album> Albums { get; set; }

		public System.Data.Entity.DbSet<MusicStore.Models.ArtistDetails> ArtistDetails { get; set; }
	}
}


<|start_filename|>ChristopherDemos/MusicStore/Models/Reviewer.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MusicStore.Models
{
	public class Reviewer
	{
		public int ReviewerID { get; set; }
		public string Name { get; set; }

		public virtual List<Album> Albums { get; set; }
	}
}


<|start_filename|>AdamDemos/ConnectionResiliency Console Demo/ConnectionResiliency/Program.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Infrastructure.Interception;
using System.Data.Entity.SqlServer;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConnectionResiliency
{
    class Program
    {
        static void Main(string[] args)
        {
            //Add an interceptor to force a fake db connection issue
            //so we can see the connection retry at work. This intercepts
            //ReaderExecuting to force the exception.
            DbInterception.Add(new InterceptorForceTransientErrors());

            //Add an interceptor to log our details so we can log
            //out the details each step of the way
            DbInterception.Add(new InterceptorForLogging());


            using (var context = new MusicContext())
            {
                Console.WriteLine("Adding album");
                context.Albums.Add(new Album()
                {
                    Title = "My Album",
                    Price = 9.99m
                });

                context.SaveChanges();

                Console.WriteLine("Attempting query (Interceptor will now fake a connection error to trigger retry)");
                
                //To force our exception, one of our parameters needs to have
                //the word Throw. Thats how our connection interceptor knows to fake an error

                try
                {
                    var count = context.Albums.Where(o => o.Title.Contains("FakeAnError")).Count();

                }
                catch (RetryLimitExceededException)
                {
                    Console.WriteLine("Caught RetryLimitExceededException, connection retry worked.");

                    Console.WriteLine("Press enter to continue...");
                    Console.ReadLine();
                    return;
                }
                //Shouldn't get here :)
                foreach (var album in context.Albums.ToList())
                {
                    Console.WriteLine(
                        string.Format("Id:{0}\nTitle:{1}\nPrice:{2}\n\n",
                        album.AlbumId, album.Title, album.Price));
                }
            }
            Console.WriteLine("Press enter to continue...");
            Console.ReadLine();
        }
    }
    public class ConnectionConfiguration : DbConfiguration
    {
        public ConnectionConfiguration()
        {
           SetExecutionStrategy("System.Data.SqlClient", () => new SqlAzureExecutionStrategy(3, new TimeSpan(0, 0, 5)));
        }
    }

    public class Album
    {
        public int AlbumId { get; set; }
        public string Title { get; set; }
        public decimal Price { get; set; }
    }

    public class MusicContext : DbContext
    {
        public DbSet<Album> Albums { get; set; }
    }
}


<|start_filename|>ChristopherDemos/MusicStore/Models/SoloArtist.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MusicStore.Models
{
	public class SoloArtist : Artist
	{
		public string Instrument { get; set; }
	}
}


<|start_filename|>AdamDemos/Guid Primary Key Demo/Guid Primary Key Demo/Program.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Guid_Primary_Key_Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var context = new MusicContext())
            {
                context.Albums.Add(new Album()
                {
                    Title = "My Album",
                    Price = 9.99m
                });

                context.SaveChanges();

                foreach (var album in context.Albums.ToList())
                {
                    Console.WriteLine(
                        string.Format("Id:{0}\nTitle:{1}\nPrice:{2}\n\n", 
                        album.AlbumId, album.Title, album.Price));
                }
            }

            Console.WriteLine("Press enter to continue...");
            Console.ReadLine();

        }
    }

    public class Album
    {
        /// <summary>
        /// You'll notice when we do an update-database -script the sql that is generated contains
        /// the code to generate a new Guid upon insert
        /// CREATE TABLE [dbo].[Albums] (
        ///    [AlbumId] [uniqueidentifier] NOT NULL DEFAULT newsequentialid(),
        ///    [Title] [nvarchar](max),
        ///    [Price] [decimal](18, 2) NOT NULL,
        ///    CONSTRAINT [PK_dbo.Albums] PRIMARY KEY ([AlbumId])
        ///)
        /// </summary>
        public Guid AlbumId { get; set; }
        public string Title { get; set; }
        public decimal Price { get; set; }
    }

    public class MusicContext : DbContext
    {
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Album>().Property(o => o.AlbumId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            base.OnModelCreating(modelBuilder);
        }
        public DbSet<Album> Albums { get; set; }
    }

}


<|start_filename|>ChristopherDemos/MusicStore/Models/Album.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MusicStore.Models
{
	public class Album
	{
		public int AlbumID { get; set; }

		[Required()]
		[StringLength(100, MinimumLength = 2)]
		public String Title { get; set; }

		public int ArtistID { get; set; }
		public virtual Artist Artist { get; set; }
		public virtual List<Reviewer> Reviewers { get; set; }
	}
}


<|start_filename|>AdamDemos/ConcurrencyDetectionAndUserChoice/ConcurrencyDetectionAndUserChoice/Views/Albums/Index.cshtml<|end_filename|>
﻿@model IEnumerable<ConcurrencyDetectionAndUserChoice.Album>

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

<pre>
Note that to get this demo to work, add an album.
After you save it and get back to the Index page (this one) you'll right click on 'Edit'
to open up a new tab. Edit in one, save it, edit in the other and save it.
Visual Studio will break in your code with an DbUpdateConcurrencyException, press f5 to continue. 
Voila.
</pre>
<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Title)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Price)
        </th>
        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Title)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Price)
        </td>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id=item.AlbumId }) |
            @Html.ActionLink("Details", "Details", new { id=item.AlbumId }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.AlbumId })
        </td>
    </tr>
}

</table>
