public void Save(params ContentType[] contentTypes)
        {
            using (var ts = new TransactionScope())
            using (var dataContext = new ContentDataContext(connectionString))
            {
                var loadOptions = new DataLoadOptions();
                loadOptions.LoadWith<ContentTypeItem>(ct => ct.ContentActionItems);

                dataContext.LoadOptions = loadOptions;

                var contentTypeItems = dataContext.ContentTypeItems.ToList();
                var itemsToDelete = from data in contentTypeItems
                                    where !contentTypes.Any(t => t.Type == data.Type && t.ControllerName == data.ControllerName)
                                    select data;

                var itemsToUpdate = (from data in contentTypeItems
                                     let type = contentTypes.SingleOrDefault(t => t.Type == data.Type && t.ControllerName == data.ControllerName)
                                     where type != null
                                     select new { data, type }).ToList();

                var itemsToInsert = (from type in contentTypes
                                     where !contentTypeItems.Any(t => t.Type == type.Type && t.ControllerName == type.ControllerName)
                                     select CreateContentTypeItem(type)).ToList();

                itemsToUpdate.ForEach(i => UpdateContentTypeItem(i.data, i.type, dataContext));

                dataContext.ContentTypeItems.DeleteAllOnSubmit(itemsToDelete);
                dataContext.ContentTypeItems.InsertAllOnSubmit(itemsToInsert);

                dataContext.SubmitChanges();
                ts.Complete();
            }
        }
        public ContentType[] GetContentTypes()
        {
            var contentTypes = cache["ContentTypes"] as ContentType[];

            if (contentTypes == null)
            {
                using (var dataContext = new ContentDataContext(connectionString))
                {
                    var types = dataContext.ContentTypeItems.ToArray();
                    var actions = dataContext.ContentActionItems.ToArray();

                    contentTypes = (from type in types
                                    select new ContentType(type.Type, type.DisplayName, type.ControllerName, actions.Where(c => c.ContentType == type.Type)
                                                                                                                 .Select(a => new ContentAction
                                                                                                                 {
                                                                                                                     Action = a.Action,
                                                                                                                     DisplayName =
                                                                                                                         a.DisplayName
                                                                                                                 }).ToArray())
                                   ).ToArray();

                    cache.Add("ContentTypes", contentTypes, new DateTimeOffset(DateTime.Now.AddHours(1)));
                }
            }

            return contentTypes;
        }
        public ContentTree GetContentTree()
        {
            using(var dataContext = new ContentDataContext(connectionString))
            {
                var contentTreeItems = contentTreeCache.Get(ContentTreeCacheKey) as ContentTreeItem[];
                if (contentTreeItems == null)
                {
                    contentTreeItems = dataContext.ContentTreeItems.ToArray();
                    contentTreeCache.Set(ContentTreeCacheKey, contentTreeItems, new DateTimeOffset(DateTime.Now.AddHours(1)));
                }

                var nodes = (from contentTreeItem in contentTreeItems
                             select new ContentNode
                                        {
                                            Action = contentTreeItem.Action,
                                            Controller = contentTreeItem.Controller,
                                            Id = contentTreeItem.Id,
                                            ParentId = contentTreeItem.ParentId,
                                            Segment = contentTreeItem.Segment,
                                            ActionId = contentTreeItem.ActionId,
                                            TreeNodeId = contentTreeItem.TreeNodeId,
                                        });

                return ContentTree.BuildTree(nodes);
            }
        }
 private void CreateContentTreeTableIfNecessary(ContentDataContext dataContext)
 {
     try
     {
         var items = dataContext.ContentTreeItems.Take(1).ToArray();
     }catch(Exception exception)
     {
         if (exception.Message == "Invalid object name 'dbo.ContentTree'.")
         {
             dataContext.ExecuteCommand(string.Format(@"
                                 CREATE TABLE [dbo].[ContentTree](
                                     [Id] [nvarchar](50) NOT NULL,
                                     [ParentId] [nvarchar](50) NOT NULL,
                                     [Segment] [nvarchar](500) NULL,
                                     [Action] [nvarchar](500) NULL,
                                     [Controller] [nvarchar](500) NULL,
                                     [TreeNodeId] [nvarchar](50) NULL,
                                     [ActionId] [nvarchar](50) NULL,
                                     CONSTRAINT [PK_ContentTreeItem] PRIMARY KEY CLUSTERED
                                 (
                                     [Id] ASC
                                 )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
                                 ) ON [PRIMARY]
                                 "), new object[]{});
         }
     }
 }
        private static void UpdateContentTypeItem(ContentTypeItem contentTypeItem, ContentType contentType, ContentDataContext contentDataContext)
        {
            contentTypeItem.DisplayName = contentType.DisplayName;

            var actionsToDelete = (from item in contentTypeItem.ContentActionItems
                                   where !contentType.Actions.Any(action => action.Action == item.Action)
                                   select item).ToList();

            var actionsToUpdate = (from item in contentTypeItem.ContentActionItems
                                   let action = contentType.Actions.SingleOrDefault(a => a.Action == item.Action)
                                   where action != null
                                   select new { item, action }).ToList();

            var actionsToInsert = (from action in contentType.Actions
                                   where !contentTypeItem.ContentActionItems.Any(a => a.Action == action.Action)
                                   select new ContentActionItem { Action = action.Action, ContentType = contentTypeItem.Type, DisplayName = action.DisplayName }).
                ToList();

            contentDataContext.ContentActionItems.DeleteAllOnSubmit(actionsToDelete);
            actionsToUpdate.ForEach(a => { a.item.DisplayName = a.action.DisplayName; });
            contentTypeItem.ContentActionItems.AddRange(actionsToInsert);
        }
 private void EnsureNecessaryTablesExist(string connectionString)
 {
     using (var dataContext = new ContentDataContext(connectionString))
     {
         CreateContentTreeTableIfNecessary(dataContext);
         CreateContentTypesTableIfNecessary(dataContext);
         CreateContentActionsTableIfNecessary(dataContext);
     }
 }