/// <summary>
        /// Adds the specified user names to the specified roles for the configured applicationName.
        /// </summary>
        /// <param name="userNames">A string array of user names to be added to the specified roles.</param>
        /// <param name="roleNames">A string array of the role names to add the specified user names to.</param>
        public override void AddUsersToRoles(string[] userNames, string[] roleNames)
        {
            using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
            {
                IQueryable<Role> roles = context.Role.Where(MatchRoleApplication()).Where(ProviderUtils.BuildContainsExpression<Role, string>(r => r.Name, roleNames));
                if (roles.Count() != roleNames.Length)
                {
                    throw new ProviderException("Role not found.");
                }

                IQueryable<User> users = context.User.Where(MatchUserApplication()).Where(ProviderUtils.BuildContainsExpression<User, string>(u => u.Username, userNames));
                if (users.Count() != userNames.Length)
                {
                    throw new ProviderException("User not found.");
                }

                try
                {
                    foreach (User user in users)
                    {
                        foreach (Role role in roles)
                        {
                            // Check whether user is already in role
                            if (IsUserInRole(user.Username, role.Name))
                            {
                                throw new ProviderException(string.Format("User is already in role '{0}'.", role.Name));
                            }

                            user.Role.Add(role);
                        }
                    }

                    context.SaveChanges(false);
                }
                catch (Exception ex)
                {
                    if (WriteExceptionsToEventLog)
                    {
                        WriteToEventLog(ex, "AddUsersToRoles");
                    }
                    else
                    {
                        throw;
                    }
                }
                finally
                {
                    context.Connection.Close();
                }
            }
        }
        /// <summary>
        /// When overridden in a derived class, deletes all user-profile data for profiles in which the last activity date occurred before the specified date.
        /// </summary>
        /// <returns>The number of profiles deleted from the data source.</returns>
        /// <param name="authenticationOption">One of the <see cref="T:System.Web.Profile.ProfileAuthenticationOption" /> values, specifying 
        /// whether anonymous, authenticated, or both types of profiles are deleted.</param>
        /// <param name="userInactiveSinceDate">A <see cref="T:System.DateTime" /> that identifies which user profiles are considered 
        /// inactive. If the <see cref="P:System.Web.Profile.ProfileInfo.LastActivityDate" />  value of a user profile occurs on or before 
        /// this date and time, the profile is considered inactive.</param>
        public override int DeleteInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate)
        {
            int num = 0;

            using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
            {
                IQueryable<DataLayer.Profile> profiles = context.User.Where(MatchUserApplication())
                                                                     .Where(ApplyAuthenticationOption(authenticationOption))
                                                                     .Where(u => u.LastActivityDate <= userInactiveSinceDate.ToUniversalTime())
                                                                     .Select(u => u.Profile);

                foreach (DataLayer.Profile profile in profiles)
                {
                    context.DeleteObject(profile);
                    num++;
                }

                context.SaveChanges();
            }

            return num;
        }
 /// <summary>
 /// Gets a value indicating whether the specified role name already exists in the role data source for the configured applicationName.
 /// </summary>
 /// <returns>true if the role name already exists in the data source for the configured applicationName; otherwise, false.</returns>
 /// <param name="roleName">The name of the role to search for in the data source.</param>
 public override bool RoleExists(string roleName)
 {
     using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
     {
         try
         {
             return GetRole(r => r.Name == roleName, context) != null;
         }
         catch (ProviderException)
         {
             return false;
         }
     }
 }
        /// <summary>
        /// Removes the specified user names from the specified roles for the configured applicationName.
        /// </summary>
        /// <param name="userNames">A string array of user names to be removed from the specified roles.</param>
        /// <param name="roleNames">A string array of role names to remove the specified user names from.</param>
        public override void RemoveUsersFromRoles(string[] userNames, string[] roleNames)
        {
            using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
            {
                IQueryable<Role> roles = context.Role.Where(MatchRoleApplication()).Where(ProviderUtils.BuildContainsExpression<Role, string>(r => r.Name, roleNames));
                if (roles.Count() != roleNames.Length)
                {
                    throw new ProviderException("Role not found.");
                }

                IQueryable<User> users = context.User.Include("Role").Where(MatchUserApplication()).Where(ProviderUtils.BuildContainsExpression<User, string>(u => u.Username, userNames));
                if (users.Count() != userNames.Length)
                {
                    throw new ProviderException("User not found.");
                }

                try
                {
                    foreach (User user in users)
                    {
                        foreach (Role role in roles)
                        {
                            /*if (!user.Role.IsLoaded)
                            {
                                user.Role.Load();
                            }*/

                            if (user.Role.Contains(role))
                            {
                                user.Role.Remove(role);
                            }
                        }
                    }

                    context.SaveChanges();
                }
                catch (Exception ex)
                {
                    if (WriteExceptionsToEventLog)
                    {
                        WriteToEventLog(ex, "RemoveUsersFromRoles");
                    }
                    else
                    {
                        throw;
                    }
                }
            }
        }
        /// <summary>
        /// Gets a value indicating whether the specified user is in the specified role for the configured applicationName.
        /// </summary>
        /// <param name="username">The user name to search for.</param>
        /// <param name="roleName">The role to search in.</param>
        /// <returns>true if the specified user is in the specified role for the configured applicationName; otherwise, false.</returns>
        public override bool IsUserInRole(string username, string roleName)
        {
            try
            {
                using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
                {
                    if (!EFMembershipProvider.CheckUser(username, ApplicationName, context))
                    {
                        return false;
                    }

                    return (from u in context.User
                            where u.Username == username && u.Application.Name == ApplicationName
                            from r in u.Role
                            where r.Name == roleName && r.Application.Name == ApplicationName
                            select r).Count() > 0;
                }
            }
            catch (Exception ex)
            {
                if (WriteExceptionsToEventLog)
                {
                    WriteToEventLog(ex, "IsUserInRole");
                }

                throw;
            }
        }
        /// <summary>
        /// Gets a list of users in the specified role for the configured applicationName.
        /// </summary>
        /// <param name="roleName">The name of the role to get the list of users for.</param>
        /// <returns>
        /// A string array containing the names of all the users who are members of the specified role for the configured applicationName.
        /// </returns>
        public override string[] GetUsersInRole(string roleName)
        {
            using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
            {
                Role role = GetRole(r => r.Name == roleName, context);
                if (role == null)
                {
                    throw new ProviderException("Role not found.");
                }

                if (!role.User.IsLoaded)
                {
                    role.User.Load();
                }

                return role.User.Select(u => u.Name).ToArray();
            }
        }
        /// <summary>
        /// Gets a list of the roles that a specified user is in for the configured applicationName.
        /// </summary>
        /// <param name="username">The user to return a list of roles for.</param>
        /// <returns>A string array containing the names of all the roles that the specified user is in for the configured applicationName.</returns>
        public override string[] GetRolesForUser(string username)
        {
            using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
            {
                if (!EFMembershipProvider.CheckUser(username, ApplicationName, context))
                {
                    throw new ArgumentNullException("username");
                }

                return (from u in context.User
                        where u.Username == username && u.Application.Name == ApplicationName
                        from r in u.Role
                        where r.Application.Name == ApplicationName
                        select r.Name).ToArray();
            }
        }
 /// <summary>
 /// Gets a list of all the roles for the configured applicationName.
 /// </summary>
 /// <returns>A string array containing the names of all the roles stored in the data source for the configured applicationName.</returns>
 public override string[] GetAllRoles()
 {
     using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
     {
         return context.Role.Where(MatchRoleApplication()).Select(r => r.Name).ToArray();
     }
 }
        /// <summary>
        /// When overridden in a derived class, retrieves profile information for profiles in which the last activity date occurred on or before the specified date and the user name matches the specified user name.
        /// </summary>
        /// <returns>A <see cref="T:System.Web.Profile.ProfileInfoCollection" /> containing user profile information for inactive profiles where the user name matches the supplied <paramref name="usernameToMatch" /> parameter.
        /// </returns>
        /// <param name="authenticationOption">One of the <see cref="T:System.Web.Profile.ProfileAuthenticationOption" /> values, specifying whether anonymous, authenticated, or both types of profiles are returned.</param>
        /// <param name="usernameToMatch">The user name to search for.</param>
        /// <param name="userInactiveSinceDate">A <see cref="T:System.DateTime" /> that identifies which user profiles are considered inactive. If the <see cref="P:System.Web.Profile.ProfileInfo.LastActivityDate" /> value of a user profile occurs on or before this date and time, the profile is considered inactive.</param>
        /// <param name="pageIndex">The index of the page of results to return.</param>
        /// <param name="pageSize">The size of the page of results to return.</param>
        /// <param name="totalRecords">When this method returns, contains the total number of profiles.</param>
        public override ProfileInfoCollection FindInactiveProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords)
        {
            ProfileInfoCollection profileCollection = new ProfileInfoCollection();

            using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
            {
                IQueryable<ProfileInfo> profiles = context.User.Where(MatchUserApplication())
                                                               .Where(ApplyAuthenticationOption(authenticationOption))
                                                               .Where(u => u.Username.Contains(usernameToMatch) && u.LastActivityDate <= userInactiveSinceDate.ToUniversalTime())
                                                               .Skip(pageIndex * pageSize)
                                                               .Take(pageSize)
                                                               .Select(u => new ProfileInfo(u.Username, u.IsAnonymous, u.LastActivityDate, u.Profile.LastUpdatedDate, GetSize(u)));
                foreach (ProfileInfo profileInfo in profiles)
                {
                    profileCollection.Add(profileInfo);
                }

                totalRecords = context.User.Where(MatchUserApplication())
                                           .Where(ApplyAuthenticationOption(authenticationOption))
                                           .Where(u => u.Username.Contains(usernameToMatch) && u.LastActivityDate <= userInactiveSinceDate.ToUniversalTime())
                                           .Count();
                return profileCollection;
            }
        }
        /// <summary>
        /// Adds a new role to the data source for the configured applicationName.
        /// </summary>
        /// <param name="roleName">The name of the role to create.</param>
        public override void CreateRole(string roleName)
        {
            // Validate role name
            if (roleName.Contains(","))
            {
                throw new ArgumentException("Role names cannot contain commas.");
            }

            if (RoleExists(roleName))
            {
                throw new ProviderException("Role name already exists.");
            }

            try
            {
                using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
                {
                    Application application = ProviderUtils.EnsureApplication(ApplicationName, context);

                    // Create new role
                    Role newRole = new Role
                                       {
                                           Id = Guid.NewGuid(),
                                           Name = roleName,
                                           Application = application
                                       };
                    context.AddToRole(newRole);
                    context.SaveChanges();
                }
            }
            catch (Exception ex)
            {
                if (WriteExceptionsToEventLog)
                {
                    WriteToEventLog(ex, "CreateRole");
                }
                else
                {
                    throw;
                }
            }
        }
        /// <summary>
        /// Gets the property values from database.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <param name="propertiesValues">The property values.</param>
        private void ExtractPropertyValuesFromDatabase(string userName, SettingsPropertyValueCollection propertiesValues)
        {
            string[] propertyNames = null;
            string propertiesValuesSerialized = null;
            byte[] propertiesValuesBinary = null;

            using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
            {
                User user = context.User.Include("Profile").Where(MatchUserApplication()).Where(u => u.Username == userName && u.Profile != null).FirstOrDefault();
                if (user != null)
                {
                    propertyNames = user.Profile.PropertyNames.Split(new[] { ':' });
                    propertiesValuesSerialized = user.Profile.PropertyValuesString;
                    propertiesValuesBinary = user.Profile.PropertyValuesBinary;

                    // Update user
                    user.LastActivityDate = DateTime.Now;
                    context.SaveChanges();
                }
            }

            ParseDataFromDatabase(propertyNames, propertiesValuesSerialized, propertiesValuesBinary, propertiesValues);
        }
        /// <summary>
        /// Sets the values of the specified group of property settings.
        /// </summary>
        /// <param name="context">A <see cref="T:System.Configuration.SettingsContext" /> describing the current application usage.</param>
        /// <param name="properties">A <see cref="T:System.Configuration.SettingsPropertyValueCollection" /> representing the group 
        /// of property settings to set.</param>
        public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection properties)
        {
            string username = (string)context["UserName"];

            if (string.IsNullOrEmpty(username) || properties.Count < 1)
            {
                return;
            }

            bool userIsAuthenticated = (bool)context["IsAuthenticated"];
            string propertiesNames = string.Empty;
            string propertiesValuesSerialized = string.Empty;
            byte[] propertiesValuesBinary = null;

            PrepareDataForSaving(ref propertiesNames, ref propertiesValuesSerialized, ref propertiesValuesBinary, properties, userIsAuthenticated);

            if (propertiesNames.Length != 0)
            {
                using (EFDataModelEntities dataContext = new EFDataModelEntities(connectionString))
                {
                    // Attempt to load user with associated profile
                    User user = dataContext.User.Include("Profile").Where(MatchUserApplication()).Where(u => u.Username == username).FirstOrDefault();

                    if (user == null)
                    {
                        throw new ArgumentException("user");
                    }

                    if (user.Profile == null)
                    {
                        // Create new profile
                        user.Profile = new DataLayer.Profile();
                    }

                    // Set profile values
                    user.Profile.PropertyNames = propertiesNames;
                    user.Profile.PropertyValuesString = propertiesValuesSerialized;
                    user.Profile.PropertyValuesBinary = propertiesValuesBinary;
                    user.Profile.LastUpdatedDate = DateTime.Now;
                    dataContext.SaveChanges();
                }
            }
        }
 /// <summary>
 /// When overridden in a derived class, returns the number of profiles in which the last activity date occurred on or before the specified date.
 /// </summary>
 /// <returns>The number of profiles in which the last activity date occurred on or before the specified date.</returns>
 /// <param name="authenticationOption">One of the <see cref="T:System.Web.Profile.ProfileAuthenticationOption" /> values, specifying 
 /// whether anonymous, authenticated, or both types of profiles are returned.</param>
 /// <param name="userInactiveSinceDate">A <see cref="T:System.DateTime" /> that identifies which user profiles are considered inactive. 
 /// If the <see cref="P:System.Web.Profile.ProfileInfo.LastActivityDate" />  of a user profile occurs on or before this date and time, 
 /// the profile is considered inactive.</param>
 public override int GetNumberOfInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate)
 {
     using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
     {
         IQueryable<DataLayer.Profile> profiles = context.User.Where(MatchUserApplication())
                                                              .Where(ApplyAuthenticationOption(authenticationOption))
                                                              .Where(u => u.LastActivityDate <= userInactiveSinceDate.ToUniversalTime())
                                                              .Select(u => u.Profile);
         return profiles.Count();
     }
 }
        /// <summary>
        /// When overridden in a derived class, retrieves user profile data for all profiles in the data source.
        /// </summary>
        /// <returns>A <see cref="T:System.Web.Profile.ProfileInfoCollection" /> containing user-profile information for all profiles in the data source.</returns>
        /// <param name="authenticationOption">One of the <see cref="T:System.Web.Profile.ProfileAuthenticationOption" /> values, specifying whether anonymous, authenticated, or both types of profiles are returned.</param>
        /// <param name="pageIndex">The index of the page of results to return.</param>
        /// <param name="pageSize">The size of the page of results to return.</param>
        /// <param name="totalRecords">When this method returns, contains the total number of profiles.</param>
        public override ProfileInfoCollection GetAllProfiles(ProfileAuthenticationOption authenticationOption, int pageIndex, int pageSize, out int totalRecords)
        {
            ProfileInfoCollection profileCollection = new ProfileInfoCollection();

            using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
            {
                IQueryable<ProfileInfo> profiles = context.User.Where(MatchUserApplication())
                                                               .Where(ApplyAuthenticationOption(authenticationOption))
                                                               .Skip(pageIndex * pageSize)
                                                               .Take(pageSize)
                                                               .Select(u => new ProfileInfo(u.Username, u.IsAnonymous, u.LastActivityDate, u.Profile.LastUpdatedDate, GetSize(u)));
                foreach (ProfileInfo profileInfo in profiles)
                {
                    profileCollection.Add(profileInfo);
                }

                totalRecords = context.User.Where(MatchUserApplication()).Where(ApplyAuthenticationOption(authenticationOption)).Count();
                return profileCollection;
            }
        }
        /// <summary>
        /// Get role from database. Throws an error if the role could not be found.
        /// </summary>
        /// <param name="query">The role query.</param>
        /// <param name="context">The context.</param>
        /// <returns>Found role entity.</returns>
        private Role GetRole(Expression<Func<Role, bool>> query, EFDataModelEntities context)
        {
            Role role = context.Role.Where(query).Where(MatchRoleApplication()).FirstOrDefault();
            if (role == null)
            {
                throw new ProviderException("The supplied role name could not be found.");
            }

            return role;
        }
        /// <summary>
        /// Removes a role from the data source for the configured applicationName.
        /// </summary>
        /// <param name="roleName">The name of the role to delete.</param>
        /// <param name="throwOnPopulatedRole">If true, throw an exception if <paramref name="roleName"/> has one or more members and do not delete <paramref name="roleName"/>.</param>
        /// <returns>
        /// true if the role was successfully deleted; otherwise, false.
        /// </returns>
        public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            // Validate role
            if (!RoleExists(roleName))
            {
                throw new ProviderException("Role does not exist.");
            }

            if (throwOnPopulatedRole && GetUsersInRole(roleName).Length > 0)
            {
                throw new ProviderException("Cannot delete a populated role.");
            }

            using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
            {
                Role role = GetRole(r => r.Name == roleName, context);
                if (role == null)
                {
                    return false;
                }

                try
                {
                    context.DeleteObject(role);
                    context.SaveChanges();
                }
                catch (Exception ex)
                {
                    if (WriteExceptionsToEventLog)
                    {
                        WriteToEventLog(ex, "DeleteRole");
                        return false;
                    }

                    throw;
                }

                return true;
            }
        }
        /// <summary>
        /// When overridden in a derived class, deletes profile properties and information for profiles that match the supplied list of user names.
        /// </summary>
        /// <returns>The number of profiles deleted from the data source.</returns>
        /// <param name="usernames">A string array of user names for profiles to be deleted.</param>
        public override int DeleteProfiles(string[] usernames)
        {
            int num = 0;

            using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
            {
                IQueryable<User> users = context.User.Include("Profile").Where(u => usernames.Contains(u.Username) && u.Profile != null);

                foreach (User user in users)
                {
                    context.DeleteObject(user.Profile);
                    num++;
                }

                context.SaveChanges();
            }

            return num;
        }