C#, EF Entity Framework, Reflection, UTC

Converting all date/time properties of an object graph to local time from UTC

Backstory: In a project I am working on, I am storing all times in the database as UTC. When I get the values from the database, I want to convert the times to local time to be displayed in my client. There’s many articles on this, that involve changing to local time on the server before shipping to client, which I didn’t care for (for example, hooking into the ObjectMaterialized event on the ObjectContext and using reflection). This had to be done on the client itself to take advantage of the client’s time zone.

I didn’t want to convert them all by hand, either. What if I added D/T properties later? If it’s nullable, then it’s an extra line of code to check that it’s not null first. What about an object graph (nested objects)? It sounded like a lot of work, until I cobbled together this code from a couple sources and reworked it a bit to do what I want:

	/// <summary>
	/// Since all dates in the DB are stored as UTC, this converts dates to the local time using the Windows time zone settings.
	/// </summary>
	public static class AllDateTimesAsUTC
	{

		/// <summary>
		/// Specifies that an object's dates are coming in as UTC.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="obj"></param>
		/// <returns></returns>
		public static T AllDatesAreUTC<T>(this T obj)
		{
			if (obj == null)
			{
				return default(T);
			}
			IterateDateTimeProperties(obj);
			return obj;
		}

		private static void IterateDateTimeProperties(object obj)
		{
			if (obj == null)
			{
				return;
			}
			var properties = obj.GetType().GetProperties();
			//Set all DaetTimeKinds to Utc
			foreach (var prop in properties)
			{
				var t = prop.PropertyType;
				if (t == typeof(DateTime) || t == typeof(DateTime?))
				{
					SpecifyUtcKind(prop, obj);
				}
				else if (t.IsEnumerable())
				{
					var vals = prop.GetValue(obj, null);
					if (vals != null)
					{
						foreach (object o in (IEnumerable)vals)
						{
							IterateDateTimeProperties(o);
						}
					}
				}
				else
				{
					var val = prop.GetValue(obj, null);
					if (val != null)
					{
						IterateDateTimeProperties(val);
					}
				}
			}
			//properties.ForEach(property => SpecifyUtcKind(property, obj));
			return; // obj;
		}

		private static void SpecifyUtcKind(PropertyInfo property, object value)
		{
			//Get the datetime value
			var datetime = property.GetValue(value, null);
			DateTime output;

			//set DateTimeKind to Utc
			if (property.PropertyType == typeof(DateTime))
			{
				output = DateTime.SpecifyKind((DateTime)datetime, DateTimeKind.Utc);
			}
			else if (property.PropertyType == typeof(DateTime?))
			{
				var nullable = (DateTime?)datetime;
				if (!nullable.HasValue) return;
				output = (DateTime)DateTime.SpecifyKind(nullable.Value, DateTimeKind.Utc);
			}
			else
			{
				return;
			}

			Debug.WriteLine("     ***** Converted date from {0} to {1}.", datetime, output);
			datetime = output.ToLocalTime();

			//And set the Utc DateTime value
			property.SetValue(value, datetime, null);
		}
		internal static Type[] ConvertibleTypes = {typeof(bool), typeof(byte), typeof(char),
   typeof(DateTime), typeof(decimal), typeof(double), typeof(float), typeof(int), 
   typeof(long), typeof(sbyte), typeof(short), typeof(string), typeof(uint), 
   typeof(ulong), typeof(ushort)};

		/// <summary>
		/// Returns true if this Type matches any of a set of Types.
		/// </summary>
		/// <param name="types">The Types to compare this Type to.</param>
		public static bool In(this Type type, params Type[] types)
		{
			foreach (Type t in types) if (t.IsAssignableFrom(type)) return true; return false;
		}

		/// <summary>
		/// Returns true if this Type is one of the types accepted by Convert.ToString() 
		/// (other than object).
		/// </summary>
		public static bool IsConvertible(this Type t) { return t.In(ConvertibleTypes); }

		/// <summary>
		/// Gets whether this type is enumerable.
		/// </summary>
		public static bool IsEnumerable(this Type t)
		{
			return typeof(IEnumerable).IsAssignableFrom(t);
		}

		/// <summary>
		/// Returns true if this property's getter is public, has no arguments, and has no 
		/// generic type parameters.
		/// </summary>
		public static bool SimpleGetter(this PropertyInfo info)
		{
			MethodInfo method = info.GetGetMethod(false);
			return method != null && method.GetParameters().Length == 0 &&
				 method.GetGenericArguments().Length == 0;
		}

	}

How do you use it? To change aall dates on an object sent to the client via WCF, this is how it’s done:

		void svc_ZOut_GetZOutSummaryCompleted(object sender, ZOut_GetZOutSummaryCompletedEventArgs e)
		{
			svc.ZOut_GetZOutSummaryCompleted -= new EventHandler<ZOut_GetZOutSummaryCompletedEventArgs>(svc_ZOut_GetZOutSummaryCompleted);
			svc = null;
			var whenDone = (Action<bool, ZOutResult>)e.UserState;
			if (e.Error != null)
			{
				FireOnExceptionRaised(e.Error);
				whenDone(false, null);
			}
			else
			{
				var res = e.Result.AllDatesAreUTC();
				FireOnSessionReceived(res.IsError, res.Session);
				if (res.IsError == true)
				{
					whenDone(false, null);
				}
				else
				{
					whenDone(true, res.Result);
				}
			}
		}

That’s it! It handles a whole object graph, DateTime and nullable DateTime obejcts.

Advertisement
C#, EF Entity Framework, Generics, RIA Services, Silverlight

Executing RIA Service Calls One-At-A-Time

Without going into details (because I’m not allowed to), I’m working on a RIA services app where one page has a large data-bound collection of buttons. Each button toggles a state, on or off. When the button is clicked, a RIA service call is performed to modify the state of the bound data, which sets the button state to Busy, setting a BusyIndicator to busy. When the callback returns, the busy state is turned off, and the details on the button are updated to reflect the change in data that I requested. While the button is “busy”, you’re not able to click it again until the callback is executed, which then re-enables the button. This list of buttons is in a wrap panel, and in my scenario, it represents a list of 1000+ objects whose state can be toggled on or off.

Everything was working very well, except if you clicked more than one button without waiting for the previous button’s callback to execute. On my local network, the callback time is very small (well under one second), but I could easily click a bunch of buttons really quickly, which would in turn cause RIA services to try to execute more than one call to update data at a time, which is not allowed.

InvalidOperationException: A SubmitChanges operation is already in progress on this DomainContext.

That throws a wrench in my gears! My options were:

  1. Add a BusyIndicator to the wrap panel, and setting it to be busy after each click;
  2. Try to get the calls to execute one-at-a-time by queuing them.

The first option was considered, but the problem there is that no other button could be toggled while the RIA service was running. Speed in clicking buttons in this list is key, and having the whole wrap panel be busy and not busy would make it flash a lot, and it’s just not as clean as having the RIA service calls execute in a queue.

My ExecuteOneAtATimeQueue class takes care of queuing RIA service calls, or any other asynchronous calls that can only run one-at-a-time such as WebClient.

Class code:

 

using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;

namespace Derreck Dean
{


 // item being modified
 // item in queue
 // function to execute

 // 1. Object is added to the queue...
 //    a. Item (userstate) being modified
 //    b. Function defining how to load image

 internal class ExecuteOneAtATimeQueue : IDisposable, INotifyPropertyChanged
 {
 public ObservableCollection<ExecuteOneAtATimeQueueItem> Queue = null;

 public event EventHandler QueueItemWorkStarted;
 public event EventHandler QueueItemWorkCompleted;
 public event EventHandler AllQueueItemsCompleted;

 private NotifyCollectionChangedEventHandler ncceh;
 private bool canProcessQueue = false;

 public ExecuteOneAtATimeQueueItem CurrentItem {
 get {
 return _currentItem;
 }
 internal set {
 _currentItem = value;
 OnPropertyChanged("CurrentItem");
 }
 }
 private ExecuteOneAtATimeQueueItem _currentItem;

 /// <summary>
 /// Init
 /// </summary>
 public ExecuteOneAtATimeQueue() {
 ncceh = new System.Collections.Specialized
 .NotifyCollectionChangedEventHandler(Queue_CollectionChanged);
 Queue = new ObservableCollection<ExecuteOneAtATimeQueueItem>();
 Queue.CollectionChanged += ncceh;
 }

 public void BeginProcessingQueue() {
 canProcessQueue = true;
 if (Queue.Count > 0)
 processQueue();
 }

 /// <summary>
 /// Adds an item to the queue.
 /// </summary>
 /// <param name="queueItem"></param>
 public void Add(ExecuteOneAtATimeQueueItem queueItem) {
 queueItem.WorkStarted += new EventHandler(queueItem_WorkStarted);
 queueItem.WorkCompleted += new EventHandler(queueItem_WorkCompleted);
 queueItem.PropertyChanged += 
 new PropertyChangedEventHandler(queueItem_PropertyChanged);
 lock (Queue) {
 Queue.Add(queueItem);
 }
 }

 /// <summary>
 /// Called when the item in the collectiom changes
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="e"></param>
 void queueItem_PropertyChanged(object sender, PropertyChangedEventArgs e) {
 processQueue();
 }

 /// <summary>
 /// Adds work to the queue.
 /// </summary>
 /// <param name="itemToModify">Item being modified and returned.</param>
 /// <param name="userState">Optional extra data to be passed in; can be null.</param>
 /// <param name="method">Void function taking in queue item, 
 /// itemToModify and userState.</param>
 public void Add(object itemToModify, object userState, 
 Action<ExecuteOneAtATimeQueueItem, object, object> method) 
 {
 ExecuteOneAtATimeQueueItem qi = new ExecuteOneAtATimeQueueItem(itemToModify, userState);
 qi.DoWork = method;
 Add(qi);
 }

 internal void queueItem_WorkCompleted(object sender, EventArgs e) {
 if (QueueItemWorkCompleted != null) { QueueItemWorkCompleted(sender, e); }
 //processQueue(); // Continue processing queue
 }

 internal void queueItem_WorkStarted(object sender, EventArgs e) {
 if (QueueItemWorkStarted != null) { QueueItemWorkStarted(sender, e); }
 }

 /// <summary>
 /// Process the contents of the queue, if we are able.
 /// </summary>
 /// <param name="sender"></param>
 /// <param name="e"></param>
 private void Queue_CollectionChanged(object sender, 
 System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
 {
 processQueue();
 }

 /// <summary>
 /// Processes the queue if we're allowed, and starts work if we are able to.
 /// </summary>
 internal void processQueue() {
 if (canProcessQueue) {
 // See if there are any busy items in the queue. 
 // If there is not, then pop one off the stack and start executing it.
 // If there are no more items in the queue, we're finished.
 bool areAnyBusy = Queue.Any(qq => qq.IsBusy == true && qq.IsCompleted == false);
 var workToDo = Queue
 .Where(qq => qq.IsBusy == false && qq.IsCompleted == false).ToList();
 if (!areAnyBusy && workToDo.Count > 0) {
 var q = workToDo.First();
 q.StartWork();
 // Done in Item object: if (QueueItemWorkStarted != null) { 
 QueueItemWorkStarted(q, null); 
 }
 } else {
 // See if everything has been completed
 if (Queue.All(qq => qq.IsCompleted == true)) {
 if (AllQueueItemsCompleted != null) { 
 AllQueueItemsCompleted(this, new EventArgs()); 
 }
 }
 }
 }
 }

 /// <summary>
 /// Queue item for work to complete.
 /// </summary>
 internal class ExecuteOneAtATimeQueueItem : INotifyPropertyChanged
 {

 /// <summary>
 /// Time work was started.
 /// </summary>
 public DateTime? StartedWork {
 get { return _startedWork; }
 internal set {
 _startedWork = value;
 OnPropertyChanged("StartedWork");
 OnPropertyChanged("IsBusy");
 OnPropertyChanged("IsCompleted");
 }
 }
 private DateTime? _startedWork = null;

 /// <summary>
 /// Time work was completed, with or without errors.
 /// </summary>
 public DateTime? EndedWork {
 get { return _endedWork; }
 internal set {
 _endedWork = value;
 OnPropertyChanged("EndedWork");
 OnPropertyChanged("IsBusy");
 OnPropertyChanged("IsCompleted");
 }
 }
 private DateTime? _endedWork = null;

 /// <summary>
 /// The item that is being worked on
 /// </summary>
 public object ItemToModify { get; set; }

 /// <summary>
 /// Another object passed to DoWork that can be modified/used
 /// </summary>
 public object UserState { get; set; }

 /// <summary>
 /// Describes if the current item is busy or not.
 /// We know this if startedWork is null or if endedWork is not null.
 /// </summary>
 public bool IsBusy {
 // IsBusy: Work has started but not completed
 get { return (_startedWork != null && _endedWork == null); }
 }

 /// <summary>
 /// Returns true if the work for this queue item has been completed.
 /// </summary>
 public bool IsCompleted {
 get { return (_startedWork != null && _endedWork != null); }
 }

 // Describes if there was a problem running the function or not.
 public bool IsError {
 get { return _isError; }
 set { _isError = value; OnPropertyChanged("IsError"); }
 }
 private bool _isError = false;

 ////////////////////////////////////////////////////////////////////////////////////////

 internal bool _hasWorkCompletedEventBeenRaised = false;

 internal event EventHandler WorkCompleted;
 internal event EventHandler WorkStarted;

 ////////////////////////////////////////////////////////////////////////////////////////

 public ExecuteOneAtATimeQueueItem() { }
 public ExecuteOneAtATimeQueueItem(object itemToModify) {
 this.ItemToModify = itemToModify;
 }
 public ExecuteOneAtATimeQueueItem(object itemToModify, object userState) {
 this.ItemToModify = itemToModify;
 this.UserState = userState;
 }

 /// <summary>
 /// Function that is called to begin work on an item.
 /// The ExecuteOneAtATimeQueueItem.EndWork() method must be called at the 
 /// end to mark the queue item as completed.
 /// The first object is the object being modified.
 /// The second object is extra stuff that can be passed in to aid in the work being run.
 /// </summary>
 public Action<ExecuteOneAtATimeQueueItem, object, object> DoWork { get; set; }

 /// <summary>
 /// Called when work ends and the queue item can be marked as done.
 /// </summary>
 /// <param name="isError"></param>
 /// <param name="userState"></param>
 public void EndWork(bool isError, object userState) {
 EndedWork = DateTime.Now;
 this.IsError = isError;
 if (!_hasWorkCompletedEventBeenRaised) {
 if (WorkCompleted != null) { WorkCompleted(this, new EventArgs()); }
 _hasWorkCompletedEventBeenRaised = true;
 }
 }

 /// <summary>
 /// Called when work is started.
 /// </summary>
 public void StartWork() {
 if (this.IsBusy)
 throw new InvalidOperationException("Work has already started for this item.");
 StartedWork = DateTime.Now;
 if (WorkStarted != null) { WorkStarted(this, new EventArgs()); }
 if (DoWork != null) { DoWork(this, ItemToModify, UserState); }
 }

 #region INotifyPropertyChanged Members

 public event PropertyChangedEventHandler  PropertyChanged;

 internal void OnPropertyChanged(string s) {
 if (PropertyChanged != null) {
 PropertyChanged(this, new PropertyChangedEventArgs(s));
 }
 }

 #endregion
 }


 #region IDisposable Members

 public void Dispose() {
 Queue.CollectionChanged -= ncceh;
 Queue = null;
 }

 #endregion

 #region INotifyPropertyChanged Members

 public event PropertyChangedEventHandler  PropertyChanged;

 private void OnPropertyChanged(string s) {
 if (PropertyChanged != null) {
 PropertyChanged(this, new PropertyChangedEventArgs(s));
 }
 }

 #endregion
 }

}

Using The Class

Using the class is pretty easy. First, create a queue object in your viewmodel or control:

 

 private ExecuteOneAtATimeQueue queue;

Initialize the queue when you’re ready to use it:

 

 queue = new ExecuteOneAtATimeQueue();
 queue.BeginProcessingQueue();

BeginProcessingQueue() instructs the queue to start processing whatever items it already has or receives immediately. You can pre-populate the queue and then call BeginProcessingQueue(), or do what I did and just start adding items whenever you like.

So here’s my offending code, which failed when the buttons were clicked too fast:

void setObjectState(...) {
 ...
 Reference.ObjectData.SubmitChanges(so => { // BOOM
 if (callback != null) {
 if (so.HasError) {
 so.MarkErrorAsHandled();
 }
 callback(userState, so.Error);
 }
 }, true);
 ...
 }

 

Here’s the change to that call that was made, to queue it up and execute it.

 

 void setObjectState(...) {
 ...
 queue.Add(null, null, (qi, item, us) => {
 Reference.ObjectData.SubmitChanges(so => {
 if (callback != null) {
 if (so.HasError) {
 so.MarkErrorAsHandled();
 }
 callback(userState, so.Error);
 }
 qi.EndWork(so.HasError, null);
 }, true);
 });
 ...

}

I didn’t need to pass in any objects to modify during the callback, so I set both to null. In the queue.Add(…) statement, “qi” refers to the internal class instance ExecuteOneAtATimeQueueItem, which you must call EndWork() to tell the queue to move onto the next QueueItem instance and begin work. “item” and “us” (for user state) are both null, since nulls were passed in as the first two parameters to the Add() method. You can pass in two objects to work with if you need, I didn’t need them here though.

With this class, I added five lines of code to queue up RIA service calls, although your mileage may vary. Now I’m not disabling the whole wrap panel, I’m only setting each button instance to busy/disabled until the callback is called.

C#, DB Database Conversion, EF Entity Framework, Generics, Serialization

Database Conversion Script Helper Functions

Sorry it’s been so long since my last post, life has kept me quite busy!

I’m writing a database conversion script for work. I modified an older version of a database for a project and made numerous changes to the schema. Transferring data from the old database to the new database after such changes have been made is not an easy task: renamed columns are trivial, but foreign-key lookup tables are not. Making matters worse is that I can never get the SSMS Copy Database Wizard to work correctly, and when I just use the Script Database with Data option, figuring I could use some regular expressions to convert the generated script to be used with the new schema, SSMS gives me ‘Out of memory’ exceptions. Therefore, I decided to make a database conversion console program that I can run a few times, since it’s not a one-time conversion – I need to test the conversion, then have a basic version of the program for the owner of the company I work for and the end-user to test with, and then the final copy of the data to be transferred to the new database when the end-user starts working with the new software.

I came up with some helper functions I made to ease the creation of the script. Some of the tables from the old database remained unchanged in the new database, which I used _directCopy() to copy the data; for tables with changes, I used _kindaDirectCopy() to make the changes. This was done in a console program, so the static prefixes can be removed depending on your use.

/// <summary>
/// Log to screen and debug
/// </summary>
/// <param name="s"></param>
static void log(string s) {
 string op = string.Format("{0}: {1}", DateTime.Now.ToString().PadLeft(25, ' '), s);
 Console.WriteLine(op);
 Debug.WriteLine("*** " + op);
}

/// <summary> Clones an object to a similar type. The TResult and TSource must have the same properties,
/// but can be from two different namespaces.
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
static TResult cloneObjectToAnotherGraph<TSource, TResult>(TSource source) {
 MemoryStream ms = new MemoryStream();
 //BinaryFormatter bf = new BinaryFormatter();
 XmlSerializer xs = new XmlSerializer(typeof(TSource));
 //bf.Serialize(ms, source);
 xs.Serialize(ms, source);
 ms.Position = 0;
 // This part takes anything in the serialized portion that is referencing
 // "OldDB" and converting it to "NewDB" so EF doesn't gripe when I try to 
 // add the serialized object back into the new database.
 byte[] buffer = stringToBuffer(bufferToString(ms.ToArray()).Replace("OldDB", "NewDB"));
 ms.Close();
 xs = new XmlSerializer(typeof(TResult));
 //object obj = bf.Deserialize(ms);
 object obj = xs.Deserialize(new MemoryStream(buffer)); // xs.Deserialize(ms);
 ms.Close();
 TResult t = (TResult)obj;
 // Detach the entity from the old DB and attach to the new entity by creating a new entity key.
 string tn = (typeof(TResult)).ToString();
 tn = tn.Substring(tn.LastIndexOf('.') + 1);
 string key = "NewDBEntities." + tn;
 (t as EntityObject).EntityKey = newDB.CreateEntityKey(key, t);
 return t;
}

/// <summary> Converts a byte array into a string.
/// </summary>
/// <param name="buffer"></param>
/// <returns></returns>
static string bufferToString(byte[] buffer) {
 /*
 StringBuilder sb = new StringBuilder();
 foreach (byte b in buffer) {
 sb.Append(b.ToString());
 }
 return sb.ToString();
 */ 
 return System.Text.Encoding.UTF8.GetString(buffer);
}

/// <summary> Converts a string into a byte array.
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
static byte[] stringToBuffer(string s) {
 return System.Text.Encoding.UTF8.GetBytes(s);
}

/// <summary>  Gets the name of the underlying database table.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="source"></param>
/// <returns></returns>
static string getTableNameFromEntityList<T>(ObjectSet<T> source) where T : class {
 var p = source.EntitySet.ElementType.MetadataProperties.SingleOrDefault(e => e.Name == "Name");
 if (p != null) { return (string)p.Value; } else { return null; }
}

/// <summary> Turns identity insert ON or OFF for a given table in a given data context.
/// </summary>
/// <param name="store"></param>
/// <param name="tableName"></param>
/// <param name="onOff"></param>
static void setTableIdentityInsert(ObjectContext store, string tableName, bool onOff) {
 if (string.IsNullOrWhiteSpace(tableName)) { return; } // Do nothing if the table name is null or empty.
 try {
 store.ExecuteStoreCommand(string.Format("SET IDENTITY_INSERT {0} {1};",
 tableName,
 onOff ? "ON" : "OFF"));
 } catch (SqlException) {
 // Do nothing, it means that the table has no identity column
 } catch (Exception) {
 throw;
 }
}

/// <summary> Performs a direct translation of items in a source list of a type TSource into a
/// destination list of type TResult by serializing each source object and restoring it
/// into a TResult object. TSource and TResult must be the same object structure, or at
/// least able to serialize the contents of TSource and deserialize into TResult.
/// Used for database conversion scripts, where identical entities cannot be interchanged
/// normally because the types still differ (even if it is only the namespace that differs).
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="sourceList"></param>
/// <param name="destList"></param>
static void _directCopy<TSource, TResult>(ObjectSet<TSource> sourceList, ObjectSet<TResult> destList) 
 where TSource : class
 where TResult : class
{
 // Get the name of the underlying table, to turn on identity insert
 setTableIdentityInsert(newDB, getTableNameFromEntityList<TResult>(destList), true);
 long count = 0;
 sourceList.ToList().ForEach(x => {
 var y = cloneObjectToAnotherGraph<TSource, TResult>(x);
 destList.AddObject(y);
 count++;
 });
 newDB.SaveChanges(); // this can be taken out, it's just in for persistence.
 // Turns off identity insert.
 setTableIdentityInsert(newDB, getTableNameFromEntityList<TResult>(destList), false);
 log(string.Format("{0}: {1}",
 count.ToString().PadLeft(10, ' '),
 typeof(TResult).Name));
}

/// <summary> Performs a translation of items in a source list of a type TSource into a destination
/// list of type TResult by invoking a delegate/anonymous function that performs the conversion
/// of each object from TSource to a TResult.
/// If identityInsertTableName is not null, then identity insert is turned ON for the duration of
/// the call, and turned off before completing. Leave this as null if you don't want identity insert on.
/// Used for database conversion scripts where the two objects differ.
/// The counter is passed into the delegate, to be used in situations where you need an auto-incrementing
/// ID (example: When a surrogate autonumbering key is added to a table with no key/natural keys).
/// </summary>
static void _kindaDirectCopy<TSource, TResult>(ObjectSet<TSource> sourceList, ObjectSet<TResult> destList, Func<TSource, int, TResult> conversionDelegate)
 where TSource : class
 where TResult : class 
{
 setTableIdentityInsert(newDB, getTableNameFromEntityList<TResult>(destList), true);
 int counter = 0;
 sourceList.ToList().ForEach(x => {
 TResult y = conversionDelegate.Invoke(x, ++counter);
 destList.AddObject(y);
 });
 newDB.SaveChanges();
 setTableIdentityInsert(newDB, getTableNameFromEntityList<TResult>(destList), false);
}

Here’s how to use the code:

// aspnet_Applications
_directCopy<OldDB.aspnet_Applications, NewDB.aspnet_Applications>(oldDB.aspnet_Applications, newDB.aspnet_Applications);

// aspnet_SchemaVersions
_directCopy<OldDB.aspnet_SchemaVersions, NewDB.aspnet_SchemaVersions>(oldDB.aspnet_SchemaVersions, newDB.aspnet_SchemaVersions);

// aspnet_Users
_directCopy<OldDB.aspnet_Users, NewDB.aspnet_Users>(oldDB.aspnet_Users, newDB.aspnet_Users);

// aspnet_WebEvent_Events
_directCopy<OldDB.aspnet_WebEvent_Events, NewDB.aspnet_WebEvent_Events>(oldDB.aspnet_WebEvent_Events, newDB.aspnet_WebEvent_Events);
 
// aspnet_Paths
_directCopy<OldDB.aspnet_Paths, NewDB.aspnet_Paths>(oldDB.aspnet_Paths, newDB.aspnet_Paths);
 
// aspnet_Roles
_directCopy<OldDB.aspnet_Roles, NewDB.aspnet_Roles>(oldDB.aspnet_Roles, newDB.aspnet_Roles);


// Notes
_directCopy<OldDB.Note, NewDB.Note>(oldDB.Notes, newDB.Notes);

// Contact Types
_directCopy<OldDB.ContactType, NewDB.ContactType>(oldDB.ContactTypes, newDB.ContactTypes);

// Contacts - The old table had a natural key and the new table has a surrogate auto-incrementing
//        key, so I used the count parameter to give me an incrementing number to use
_kindaDirectCopy<OldDB.Contact, NewDB.Contact>(oldDB.Contacts, newDB.Contacts, (x, count) => {
 return new NewDB.Contact() {
 ContactID = count,
 ContactInfo = x.ContactInfo,
 ContactTypeID = x.ContactTypeID,
 OrganizationID = _org,
 PersonID = x.PersonID
 };
});

 

Hope this helps.