/// <summary>
        /// Inserts or updates a conference
        /// </summary>
        /// <param name="hashTag">The hashTag of the existing conference (for updates) or the hashTag of the new conference (for inserts)</param>
        /// <param name="conference">The conference itself</param>
        public void UpsertConference(string hashTag, Conference conference)
        {
            //Wrap the conference in our custom AzureTableEntity
            var table = GetTable(TableName);

            //We're using the HashTag as the RowKey, so if it gets changed we have to remove the existing record and insert a new one
            //Yes I know that if the code fails after the deletion we could be left with no conference.... Maybe look at doing this in a batch operation instead?
            //Once I move this over to SQL for part 3 we can wrap it in a transaction
            if (hashTag != conference.HashTag)
            {
                DeleteConference(hashTag);
            }

            var entity = new AzureTableEntity()
            {
                //We'll use the table name as the rowkey for now as the whole conference is being serialized in one row, thus we won't have that many rows to worry about partitioning (unless usage suddenly takes off massively!)
                PartitionKey = TableName,
                RowKey = conference.HashTag,
                //When serializing we want to make sure that object references are preserved
                Entity = JsonConvert.SerializeObject(conference, new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects })
            };

            TableOperation upsertOperation = TableOperation.InsertOrReplace(entity);

            // Insert or update the conference
            table.Execute(upsertOperation);
        }
        public ActionResult Create(Conference conference)
        {
            if (!IsConferenceHashTagAvailable(conference.HashTag))
            {
                ModelState.AddModelError("HashTag", "Unfortunately that hashtag is not available.");
            }

            if (ModelState.IsValid)
            {
                var conferenceTimeZone = TimeZoneInfo.FindSystemTimeZoneById(conference.TimeZoneId);
                conference.StartDate = TimeZoneInfo.ConvertTimeToUtc(conference.StartDate, conferenceTimeZone);
                conference.EndDate = TimeZoneInfo.ConvertTimeToUtc(conference.EndDate, conferenceTimeZone);

                YouConfDataContext.UpsertConference(conference.HashTag, conference);
                return RedirectToAction("Details", new { hashTag = conference.HashTag });
            }
            return View(conference);
        }
 //
 // GET: /Conference/Create
 public ActionResult Create()
 {
     var model = new Conference();
     return View(model);
 }
        public ActionResult Edit(string id, Conference conference)
        {
            //If the user has changed the conference hashtag we have to make sure that the new one hasn't already been taken
            if (id != conference.HashTag && !IsConferenceHashTagAvailable(conference.HashTag))
            {
                ModelState.AddModelError("HashTag", "Unfortunately that hashtag is not available.");
            }

            if (ModelState.IsValid)
            {
                var existingConference = YouConfDataContext.GetConference(id);
                if (conference == null)
                {
                    return HttpNotFound();
                }

                var conferenceTimeZone = TimeZoneInfo.FindSystemTimeZoneById(conference.TimeZoneId);
                conference.StartDate = TimeZoneInfo.ConvertTimeToUtc(conference.StartDate, conferenceTimeZone);
                conference.EndDate = TimeZoneInfo.ConvertTimeToUtc(conference.EndDate, conferenceTimeZone);

                //Could use Automapper or similar to map the new conference details onto the old so we don't lose any child properties e.g. Speakers/Presentations.
                //We'll do it manually for now
                conference.Speakers = existingConference.Speakers;
                conference.Presentations = existingConference.Presentations;

                YouConfDataContext.UpsertConference(id, conference);

                if (existingConference.HangoutId != conference.HangoutId)
                {
                    //User has changed the conference hangout id, so notify any listeners/viewers out there if they're watching (e.g. during the live conference streaming)
                    var context = GlobalHost.ConnectionManager.GetHubContext<YouConfHub>();
                    context.Clients.Group(conference.HashTag).updateConferenceVideoUrl(conference.HangoutId);
                }

                return RedirectToAction("Details", new { hashTag = conference.HashTag });
            }

            return View(conference);
        }
        private void PopulateSpeakers(Conference conference, Presentation presentation, long[] speakerIds)
        {
            presentation.Speakers.Clear();

            //Could look at creating a custom model binder here, but doing it simple for now....
            if (speakerIds == null)
                return;

            foreach (var speakerId in speakerIds)
            {
                var speaker = conference.Speakers.First(x => x.Id == speakerId);
                presentation.Speakers.Add(speaker);
            }
        }