/// <summary> /// Bind the data based on the configured category setting. /// </summary> private void BindData() { AttributeList = new List<int>(); string categoryGuid = GetAttributeValue( "Category" ); Guid guid = Guid.Empty; if ( Guid.TryParse( categoryGuid, out guid ) ) { var category = CategoryCache.Read( guid ); if ( category != null ) { if ( !string.IsNullOrWhiteSpace( category.IconCssClass ) ) { lCategoryName.Text = string.Format( "<i class='{0}'></i> {1}", category.IconCssClass, category.Name ); } else { lCategoryName.Text = category.Name; } var orderOverride = new List<int>(); GetAttributeValue( "AttributeOrder" ).SplitDelimitedValues().ToList().ForEach( a => orderOverride.Add( a.AsInteger() ) ); var orderedAttributeList = new AttributeService( new RockContext() ).GetByCategoryId( category.Id ) .OrderBy( a => a.Order ).ThenBy( a => a.Name ).ToList(); foreach ( int attributeId in orderOverride ) { var attribute = orderedAttributeList.FirstOrDefault( a => a.Id == attributeId ); if ( attribute != null && attribute.IsAuthorized( Authorization.VIEW, CurrentPerson ) ) { AttributeList.Add( attribute.Id ); } } foreach ( var attribute in orderedAttributeList.Where( a => !orderOverride.Contains( a.Id ) ) ) { if ( attribute.IsAuthorized( Authorization.VIEW, CurrentPerson ) ) { AttributeList.Add( attribute.Id ); } } } } CreateControls( true ); }
/// <summary> /// Gets the entity fields. /// </summary> /// <param name="entityType">Type of the entity.</param> /// <param name="includeOnlyReportingFields">if set to <c>true</c> [include only reporting fields].</param> /// <param name="limitToFilterableFields">if set to <c>true</c> [limit to filterable fields].</param> /// <returns></returns> public static List<EntityField> GetEntityFields( Type entityType, bool includeOnlyReportingFields = true, bool limitToFilterableFields = true ) { List<EntityField> entityFields = null; _workflowTypeNameLookup = null; if ( HttpContext.Current != null ) { entityFields = HttpContext.Current.Items[EntityHelper.GetCacheKey(entityType, includeOnlyReportingFields, limitToFilterableFields)] as List<EntityField>; if ( entityFields != null ) { return entityFields; } } if ( entityFields == null ) { entityFields = new List<EntityField>(); } // Find all non-virtual properties or properties that have the [IncludeForReporting] attribute var entityProperties = entityType.GetProperties().ToList(); var filteredEntityProperties = entityProperties .Where( p => !p.GetGetMethod().IsVirtual || p.GetCustomAttributes( typeof( IncludeForReportingAttribute ), true ).Any() || p.Name == "Order" ) .ToList(); // Get Properties foreach ( var property in filteredEntityProperties ) { bool isReportable = !property.GetCustomAttributes( typeof( HideFromReportingAttribute ), true ).Any(); if ( !includeOnlyReportingFields || isReportable ) { EntityField entityField = new EntityField( property.Name, FieldKind.Property, property ); entityField.IsPreviewable = property.GetCustomAttributes( typeof( PreviewableAttribute ), true ).Any(); var fieldTypeAttribute = property.GetCustomAttribute<Rock.Data.FieldTypeAttribute>(); // check if we can set it from the fieldTypeAttribute if ( ( fieldTypeAttribute != null ) && SetEntityFieldFromFieldTypeAttribute( entityField, fieldTypeAttribute ) ) { // intentially blank, entity field is already setup } // Enum Properties else if ( property.PropertyType.IsEnum ) { entityField.FieldType = FieldTypeCache.Read( SystemGuid.FieldType.SINGLE_SELECT.AsGuid() ); var list = new List<string>(); foreach ( var value in Enum.GetValues( property.PropertyType ) ) { list.Add( string.Format( "{0}^{1}", value, value.ToString().SplitCase() ) ); } var listSource = string.Join( ",", list ); entityField.FieldConfig.Add( "values", new Field.ConfigurationValue( listSource ) ); entityField.FieldConfig.Add( "fieldtype", new Field.ConfigurationValue( "rb" ) ); } // Boolean properties else if ( property.PropertyType == typeof( bool ) || property.PropertyType == typeof( bool? ) ) { entityField.FieldType = FieldTypeCache.Read( SystemGuid.FieldType.BOOLEAN.AsGuid() ); } // Datetime properties else if ( property.PropertyType == typeof( DateTime ) || property.PropertyType == typeof( DateTime? ) ) { var colAttr = property.GetCustomAttributes( typeof( ColumnAttribute ), true ).FirstOrDefault(); if ( colAttr != null && ( (ColumnAttribute)colAttr ).TypeName == "Date" ) { entityField.FieldType = FieldTypeCache.Read( SystemGuid.FieldType.DATE.AsGuid() ); } else { entityField.FieldType = FieldTypeCache.Read( SystemGuid.FieldType.DATE_TIME.AsGuid() ); } } // Decimal properties else if ( property.PropertyType == typeof( decimal ) || property.PropertyType == typeof( decimal? ) ) { entityField.FieldType = FieldTypeCache.Read( SystemGuid.FieldType.DECIMAL.AsGuid() ); } // Text Properties else if ( property.PropertyType == typeof( string ) ) { entityField.FieldType = FieldTypeCache.Read( SystemGuid.FieldType.TEXT.AsGuid() ); } // Integer Properties (which may be a DefinedValue) else if ( property.PropertyType == typeof( int ) || property.PropertyType == typeof( int? ) ) { entityField.FieldType = FieldTypeCache.Read( SystemGuid.FieldType.INTEGER.AsGuid() ); var definedValueAttribute = property.GetCustomAttribute<Rock.Data.DefinedValueAttribute>(); if ( definedValueAttribute != null ) { // Defined Value Properties Guid? definedTypeGuid = ( (Rock.Data.DefinedValueAttribute)definedValueAttribute ).DefinedTypeGuid; if ( definedTypeGuid.HasValue ) { var definedType = DefinedTypeCache.Read( definedTypeGuid.Value ); entityField.Title = definedType != null ? definedType.Name : property.Name.Replace( "ValueId", string.Empty ).SplitCase(); if ( definedType != null ) { entityField.FieldType = FieldTypeCache.Read( SystemGuid.FieldType.DEFINED_VALUE.AsGuid() ); entityField.FieldConfig.Add( "definedtype", new Field.ConfigurationValue( definedType.Id.ToString() ) ); } } } } if ( entityField != null && entityField.FieldType != null ) { entityFields.Add( entityField ); } } } // Get Attributes var entityTypeCache = EntityTypeCache.Read( entityType, true ); if ( entityTypeCache != null ) { int entityTypeId = entityTypeCache.Id; using ( var rockContext = new RockContext() ) { var qryAttributes = new AttributeService( rockContext ).Queryable().Where( a => a.EntityTypeId == entityTypeId ); if ( entityType == typeof( Group ) ) { // in the case of Group, show attributes that are entity global, but also ones that are qualified by GroupTypeId qryAttributes = qryAttributes .Where( a => a.EntityTypeQualifierColumn == null || a.EntityTypeQualifierColumn == string.Empty || a.EntityTypeQualifierColumn == "GroupTypeId" ); } else if ( entityType == typeof( ContentChannelItem ) ) { // in the case of ContentChannelItem, show attributes that are entity global, but also ones that are qualified by ContentChannelTypeId qryAttributes = qryAttributes .Where( a => a.EntityTypeQualifierColumn == null || a.EntityTypeQualifierColumn == string.Empty || a.EntityTypeQualifierColumn == "ContentChannelTypeId" ); } else if ( entityType == typeof( Rock.Model.Workflow ) ) { // in the case of Workflow, show attributes that are entity global, but also ones that are qualified by WorkflowTypeId (and have a valid WorkflowTypeId) var validWorkflowTypeIds = new WorkflowTypeService(rockContext).Queryable().Select(a=> a.Id).ToList().Select(a => a.ToString()).ToList(); qryAttributes = qryAttributes .Where( a => a.EntityTypeQualifierColumn == null || a.EntityTypeQualifierColumn == string.Empty || (a.EntityTypeQualifierColumn == "WorkflowTypeId" && validWorkflowTypeIds.Contains(a.EntityTypeQualifierValue) )); } else { qryAttributes = qryAttributes.Where( a => a.EntityTypeQualifierColumn == string.Empty && a.EntityTypeQualifierValue == string.Empty ); } var attributeIdList = qryAttributes.Select( a => a.Id ).ToList(); foreach ( var attributeId in attributeIdList ) { AddEntityFieldForAttribute( entityFields, AttributeCache.Read( attributeId ), limitToFilterableFields ); } } } // Order the fields by title, name int index = 0; var sortedFields = new List<EntityField>(); foreach ( var entityField in entityFields.OrderBy( p => !string.IsNullOrEmpty(p.AttributeEntityTypeQualifierName)).ThenBy( p => p.Title ).ThenBy( p => p.Name ) ) { entityField.Index = index; index++; sortedFields.Add( entityField ); } if ( HttpContext.Current != null ) { HttpContext.Current.Items[EntityHelper.GetCacheKey( entityType, includeOnlyReportingFields, limitToFilterableFields )] = sortedFields; } return sortedFields; }
/// <summary> /// Loads the cache objects. /// </summary> private void LoadCacheObjects(RockContext rockContext) { // Cache all the entity types foreach (var entityType in new Rock.Model.EntityTypeService(rockContext).Queryable().AsNoTracking()) { EntityTypeCache.Read(entityType); } // Cache all the Field Types foreach (var fieldType in new Rock.Model.FieldTypeService(rockContext).Queryable().AsNoTracking()) { Rock.Web.Cache.FieldTypeCache.Read(fieldType); } var all = Rock.Web.Cache.FieldTypeCache.All(); // Read all the qualifiers first so that EF doesn't perform a query for each attribute when it's cached var qualifiers = new Dictionary <int, Dictionary <string, string> >(); foreach (var attributeQualifier in new Rock.Model.AttributeQualifierService(rockContext).Queryable().AsNoTracking()) { try { if (!qualifiers.ContainsKey(attributeQualifier.AttributeId)) { qualifiers.Add(attributeQualifier.AttributeId, new Dictionary <string, string>()); } qualifiers[attributeQualifier.AttributeId].Add(attributeQualifier.Key, attributeQualifier.Value); } catch (Exception ex) { LogError(ex, null); } } // Cache all the attributes, except for user preferences var attributeQuery = new Rock.Model.AttributeService(rockContext).Queryable("Categories"); int?personUserValueEntityTypeId = Rock.Web.Cache.EntityTypeCache.GetId(Person.USER_VALUE_ENTITY); if (personUserValueEntityTypeId.HasValue) { attributeQuery = attributeQuery.Where(a => !a.EntityTypeId.HasValue || a.EntityTypeId.Value != personUserValueEntityTypeId); } foreach (var attribute in attributeQuery.AsNoTracking().ToList()) { if (qualifiers.ContainsKey(attribute.Id)) { Rock.Web.Cache.AttributeCache.Read(attribute, qualifiers[attribute.Id]); } else { Rock.Web.Cache.AttributeCache.Read(attribute, new Dictionary <string, string>()); } } // cache all the Country Defined Values since those can be loaded in just a few millisecond here, but take around 1-2 seconds if first loaded when formatting an address foreach (var definedValue in new Rock.Model.DefinedValueService(rockContext).GetByDefinedTypeGuid(Rock.SystemGuid.DefinedType.LOCATION_COUNTRIES.AsGuid()).AsNoTracking()) { DefinedValueCache.Read(definedValue, rockContext); } }
/// <summary> /// Loads the cache objects. /// </summary> private static void LoadCacheObjects(RockContext rockContext) { // Cache all the entity types foreach (var entityType in new Rock.Model.EntityTypeService(rockContext).Queryable().AsNoTracking()) { EntityTypeCache.Get(entityType); } // Cache all the Field Types foreach (var fieldType in new Rock.Model.FieldTypeService(rockContext).Queryable().AsNoTracking()) { // improve performance of loading FieldTypeCache by doing LoadAttributes using an existing rockContext before doing FieldTypeCache.Get to avoid calling LoadAttributes with new context per FieldTypeCache fieldType.LoadAttributes(rockContext); FieldTypeCache.Get(fieldType); } var all = FieldTypeCache.All(); // Read all the qualifiers first so that EF doesn't perform a query for each attribute when it's cached var qualifiers = new Dictionary <int, Dictionary <string, string> >(); foreach (var attributeQualifier in new Rock.Model.AttributeQualifierService(rockContext).Queryable().AsNoTracking()) { try { if (!qualifiers.ContainsKey(attributeQualifier.AttributeId)) { qualifiers.Add(attributeQualifier.AttributeId, new Dictionary <string, string>()); } qualifiers[attributeQualifier.AttributeId].Add(attributeQualifier.Key, attributeQualifier.Value); } catch (Exception ex) { var startupException = new RockStartupException("Error loading cache objects", ex); LogError(startupException, null); } } // Cache all the attributes, except for user preferences var attributeQuery = new Rock.Model.AttributeService(rockContext).Queryable("Categories"); int?personUserValueEntityTypeId = EntityTypeCache.GetId(Person.USER_VALUE_ENTITY); if (personUserValueEntityTypeId.HasValue) { attributeQuery = attributeQuery.Where(a => !a.EntityTypeId.HasValue || a.EntityTypeId.Value != personUserValueEntityTypeId); } foreach (var attribute in attributeQuery.AsNoTracking().ToList()) { // improve performance of loading AttributeCache by doing LoadAttributes using an existing rockContext before doing AttributeCache.Get to avoid calling LoadAttributes with new context per AttributeCache attribute.LoadAttributes(rockContext); if (qualifiers.ContainsKey(attribute.Id)) { Rock.Web.Cache.AttributeCache.Get(attribute, qualifiers[attribute.Id]); } else { Rock.Web.Cache.AttributeCache.Get(attribute, new Dictionary <string, string>()); } } // Force authorizations to be cached Rock.Security.Authorization.Get(); }
/// <summary> /// Loads the individual data. /// </summary> /// <param name="csvData">The CSV data.</param> private int LoadIndividuals( CSVInstance csvData ) { var lookupContext = new RockContext(); var groupTypeRoleService = new GroupTypeRoleService( lookupContext ); var groupMemberService = new GroupMemberService( lookupContext ); // Marital statuses: Married, Single, Separated, etc var maritalStatusTypes = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.PERSON_MARITAL_STATUS ), lookupContext ).DefinedValues; // Connection statuses: Member, Visitor, Attendee, etc var connectionStatusTypes = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.PERSON_CONNECTION_STATUS ), lookupContext ).DefinedValues; int memberConnectionStatusId = connectionStatusTypes.FirstOrDefault( dv => dv.Guid == new Guid( Rock.SystemGuid.DefinedValue.PERSON_CONNECTION_STATUS_MEMBER ) ).Id; int visitorConnectionStatusId = connectionStatusTypes.FirstOrDefault( dv => dv.Guid == new Guid( Rock.SystemGuid.DefinedValue.PERSON_CONNECTION_STATUS_VISITOR ) ).Id; int attendeeConnectionStatusId = connectionStatusTypes.FirstOrDefault( dv => dv.Guid == new Guid( Rock.SystemGuid.DefinedValue.PERSON_CONNECTION_STATUS_ATTENDEE ) ).Id; // Suffix type: Dr., Jr., II, etc var suffixTypes = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.PERSON_SUFFIX ), lookupContext ).DefinedValues; // Title type: Mr., Mrs. Dr., etc var titleTypes = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.PERSON_TITLE ), lookupContext ).DefinedValues; // Record statuses: Active, Inactive, Pending int? recordStatusActiveId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_ACTIVE ), lookupContext ).Id; int? recordStatusInactiveId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_INACTIVE ), lookupContext ).Id; int? recordStatusPendingId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_PENDING ), lookupContext ).Id; // Deceased record status reason (others available: No Activity, Moved, etc) var recordStatusDeceasedId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_REASON_DECEASED ) ).Id; // Record type: Person int? personRecordTypeId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.PERSON_RECORD_TYPE_PERSON ), lookupContext ).Id; // Group roles: Owner, Adult, Child, others GroupTypeRole ownerRole = groupTypeRoleService.Get( new Guid( Rock.SystemGuid.GroupRole.GROUPROLE_KNOWN_RELATIONSHIPS_OWNER ) ); int adultRoleId = groupTypeRoleService.Get( new Guid( Rock.SystemGuid.GroupRole.GROUPROLE_FAMILY_MEMBER_ADULT ) ).Id; int childRoleId = groupTypeRoleService.Get( new Guid( Rock.SystemGuid.GroupRole.GROUPROLE_FAMILY_MEMBER_CHILD ) ).Id; // Phone types: Home, Work, Mobile var numberTypeValues = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.PERSON_PHONE_TYPE ), lookupContext ).DefinedValues; // Personal note type id var personalNoteTypeId = new NoteTypeService( lookupContext ).Get( new Guid( Rock.SystemGuid.NoteType.PERSON_TIMELINE_NOTE ) ).Id; // School defined type var schoolDefinedType = DefinedTypeCache.Read( new Guid( "576FF1E2-6225-4565-A16D-230E26167A3D" ) ); // Look up existing Person attributes var personAttributes = new AttributeService( lookupContext ).GetByEntityTypeId( PersonEntityTypeId ).ToList(); var schoolAttribute = AttributeCache.Read( personAttributes.FirstOrDefault( a => a.Key == "School" ) ); // Text field type id int textFieldTypeId = FieldTypeCache.Read( new Guid( Rock.SystemGuid.FieldType.TEXT ), lookupContext ).Id; int dateFieldTypeId = FieldTypeCache.Read( new Guid( Rock.SystemGuid.FieldType.DATE ), lookupContext ).Id; // Attribute entity type id int attributeEntityTypeId = EntityTypeCache.Read( "Rock.Model.Attribute" ).Id; // Visit info category var visitInfoCategory = new CategoryService( lookupContext ).GetByEntityTypeId( attributeEntityTypeId ) .Where( c => c.Name == "Visit Information" ).FirstOrDefault(); // Look for custom attributes in the Individual file var allFields = csvData.TableNodes.FirstOrDefault().Children.Select( ( node, index ) => new { node = node, index = index } ).ToList(); Dictionary<int, string> customAttributes = allFields .Where( f => f.index > SecurityNote ) .ToDictionary( f => f.index, f => f.node.Name.RemoveWhitespace() ); // Add any attributes if they don't already exist if ( customAttributes.Any() ) { var newAttributes = new List<Rock.Model.Attribute>(); foreach ( var newAttributePair in customAttributes.Where( ca => !personAttributes.Any( a => a.Key == ca.Value ) ) ) { var newAttribute = new Rock.Model.Attribute(); newAttribute.Name = newAttributePair.Value; newAttribute.Key = newAttributePair.Value.RemoveWhitespace(); newAttribute.Description = newAttributePair.Value + " created by CSV import"; newAttribute.EntityTypeQualifierValue = string.Empty; newAttribute.EntityTypeQualifierColumn = string.Empty; newAttribute.EntityTypeId = PersonEntityTypeId; newAttribute.FieldTypeId = textFieldTypeId; newAttribute.DefaultValue = string.Empty; newAttribute.IsMultiValue = false; newAttribute.IsGridColumn = false; newAttribute.IsRequired = false; newAttribute.Order = 0; newAttributes.Add( newAttribute ); } lookupContext.Attributes.AddRange( newAttributes ); lookupContext.SaveChanges( DisableAuditing ); personAttributes.AddRange( newAttributes ); } // Set the supported date formats var dateFormats = new[] { "yyyy-MM-dd", "MM/dd/yyyy", "MM/dd/yy" }; var currentFamilyGroup = new Group(); var newFamilyList = new List<Group>(); var newVisitorList = new List<Group>(); var newNoteList = new List<Note>(); int completed = 0; int newFamilies = 0; int newPeople = 0; ReportProgress( 0, string.Format( "Starting Individual import ({0:N0} already exist).", ImportedPeopleKeys.Count() ) ); string[] row; row = csvData.Database.FirstOrDefault(); while ( row != null ) { int groupRoleId = adultRoleId; bool isFamilyRelationship = true; string rowFamilyName = row[FamilyName]; string rowFamilyKey = row[FamilyId]; string rowPersonKey = row[PersonId]; int? rowFamilyId = rowFamilyKey.AsType<int?>(); int? rowPersonId = rowPersonKey.AsType<int?>(); // Check that this person isn't already in our data var personExists = ImportedFamilies.Any( g => g.Members.Any( m => m.Person.ForeignKey == rowPersonKey ) ); if ( !personExists ) { #region person create var person = new Person(); person.ForeignKey = rowPersonKey; person.ForeignId = rowPersonId; person.SystemNote = string.Format( "Imported via Excavator on {0}", ImportDateTime ); person.RecordTypeValueId = personRecordTypeId; person.CreatedByPersonAliasId = ImportPersonAliasId; string firstName = row[FirstName].Left( 50 ); string nickName = row[NickName].Left( 50 ); person.FirstName = firstName; person.NickName = string.IsNullOrWhiteSpace( nickName ) ? firstName : nickName; person.MiddleName = row[MiddleName].Left( 50 ); person.LastName = row[LastName].Left( 50 ); DateTime createdDateValue; if ( DateTime.TryParseExact( row[CreatedDate], dateFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, out createdDateValue ) ) { person.CreatedDateTime = createdDateValue; person.ModifiedDateTime = ImportDateTime; } else { person.CreatedDateTime = ImportDateTime; person.ModifiedDateTime = ImportDateTime; } DateTime birthDate; if ( DateTime.TryParseExact( row[DateOfBirth], dateFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, out birthDate ) ) { person.BirthDay = birthDate.Day; person.BirthMonth = birthDate.Month; person.BirthYear = birthDate.Year; } DateTime graduationDate; if ( DateTime.TryParseExact( row[GraduationDate], dateFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, out graduationDate ) ) { person.GraduationYear = graduationDate.Year; } DateTime anniversary; if ( DateTime.TryParseExact( row[Anniversary], dateFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, out anniversary ) ) { person.AnniversaryDate = anniversary; } string gender = row[Gender]; if ( gender != null ) { switch ( gender.Trim().ToLower() ) { case "m": case "male": person.Gender = Rock.Model.Gender.Male; break; case "f": case "female": person.Gender = Rock.Model.Gender.Female; break; default: person.Gender = Rock.Model.Gender.Unknown; break; } } string prefix = row[Prefix]; if ( !string.IsNullOrWhiteSpace( prefix ) ) { prefix = prefix.RemoveSpecialCharacters().Trim(); person.TitleValueId = titleTypes.Where( s => prefix == s.Value.RemoveSpecialCharacters() ) .Select( s => (int?)s.Id ).FirstOrDefault(); } string suffix = row[Suffix]; if ( !string.IsNullOrWhiteSpace( suffix ) ) { suffix = suffix.RemoveSpecialCharacters().Trim(); person.SuffixValueId = suffixTypes.Where( s => suffix == s.Value.RemoveSpecialCharacters() ) .Select( s => (int?)s.Id ).FirstOrDefault(); } string maritalStatus = row[MaritalStatus]; if ( !string.IsNullOrWhiteSpace( maritalStatus ) ) { person.MaritalStatusValueId = maritalStatusTypes.Where( dv => dv.Value == maritalStatus ) .Select( dv => (int?)dv.Id ).FirstOrDefault(); } else { person.MaritalStatusValueId = maritalStatusTypes.Where( dv => dv.Value == "Unknown" ) .Select( dv => ( int? )dv.Id ).FirstOrDefault(); } string familyRole = row[FamilyRole]; if ( !string.IsNullOrWhiteSpace( familyRole ) ) { if ( familyRole == "Visitor" ) { isFamilyRelationship = false; } if ( familyRole == "Child" || person.Age < 18 ) { groupRoleId = childRoleId; } } string connectionStatus = row[ConnectionStatus]; if ( !string.IsNullOrWhiteSpace( connectionStatus ) ) { if ( connectionStatus == "Member" ) { person.ConnectionStatusValueId = memberConnectionStatusId; } else if ( connectionStatus == "Visitor" ) { person.ConnectionStatusValueId = visitorConnectionStatusId; } else { // look for user-defined connection type or default to Attendee var customConnectionType = connectionStatusTypes.Where( dv => dv.Value == connectionStatus ) .Select( dv => (int?)dv.Id ).FirstOrDefault(); person.ConnectionStatusValueId = customConnectionType ?? attendeeConnectionStatusId; person.RecordStatusValueId = recordStatusActiveId; } } string recordStatus = row[RecordStatus]; if ( !string.IsNullOrWhiteSpace( recordStatus ) ) { switch ( recordStatus.Trim().ToLower() ) { case "active": person.RecordStatusValueId = recordStatusActiveId; break; case "inactive": person.RecordStatusValueId = recordStatusInactiveId; break; default: person.RecordStatusValueId = recordStatusPendingId; break; } } string isDeceasedValue = row[IsDeceased]; if ( !string.IsNullOrWhiteSpace( isDeceasedValue ) ) { switch ( isDeceasedValue.Trim().ToLower() ) { case "y": case "yes": person.IsDeceased = true; person.RecordStatusReasonValueId = recordStatusDeceasedId; person.RecordStatusValueId = recordStatusInactiveId; break; default: person.IsDeceased = false; break; } } var personNumbers = new Dictionary<string, string>(); personNumbers.Add( "Home", row[HomePhone] ); personNumbers.Add( "Mobile", row[MobilePhone] ); personNumbers.Add( "Work", row[WorkPhone] ); string smsAllowed = row[AllowSMS]; foreach ( var numberPair in personNumbers.Where( n => !string.IsNullOrWhiteSpace( n.Value ) ) ) { var extension = string.Empty; var countryCode = Rock.Model.PhoneNumber.DefaultCountryCode(); var normalizedNumber = string.Empty; var countryIndex = numberPair.Value.IndexOf( '+' ); int extensionIndex = numberPair.Value.LastIndexOf( 'x' ) > 0 ? numberPair.Value.LastIndexOf( 'x' ) : numberPair.Value.Length; if ( countryIndex >= 0 ) { countryCode = numberPair.Value.Substring( countryIndex, countryIndex + 3 ).AsNumeric(); normalizedNumber = numberPair.Value.Substring( countryIndex + 3, extensionIndex - 3 ).AsNumeric().TrimStart( new Char[] { '0' } ); extension = numberPair.Value.Substring( extensionIndex ); } else if ( extensionIndex > 0 ) { normalizedNumber = numberPair.Value.Substring( 0, extensionIndex ).AsNumeric(); extension = numberPair.Value.Substring( extensionIndex ).AsNumeric(); } else { normalizedNumber = numberPair.Value.AsNumeric(); } if ( !string.IsNullOrWhiteSpace( normalizedNumber ) ) { var currentNumber = new PhoneNumber(); currentNumber.CountryCode = countryCode; currentNumber.CreatedByPersonAliasId = ImportPersonAliasId; currentNumber.Extension = extension.Left( 20 ); currentNumber.Number = normalizedNumber.TrimStart( new Char[] { '0' } ).Left( 20 ); currentNumber.NumberFormatted = PhoneNumber.FormattedNumber( currentNumber.CountryCode, currentNumber.Number ); currentNumber.NumberTypeValueId = numberTypeValues.Where( v => v.Value.Equals( numberPair.Key ) ) .Select( v => ( int? )v.Id ).FirstOrDefault(); if ( numberPair.Key == "Mobile" ) { switch ( smsAllowed.Trim().ToLower() ) { case "y": case "yes": case "active": currentNumber.IsMessagingEnabled = true; break; default: currentNumber.IsMessagingEnabled = false; break; } } person.PhoneNumbers.Add( currentNumber ); } } // Map Person attributes person.Attributes = new Dictionary<string, AttributeCache>(); person.AttributeValues = new Dictionary<string, AttributeValueCache>(); bool isEmailActive; switch ( row[IsEmailActive].Trim().ToLower() ) { case "n": case "no": case "inactive": isEmailActive = false; break; default: isEmailActive = true; break; } EmailPreference emailPreference; switch ( row[AllowBulkEmail].Trim().ToLower() ) { case "n": case "no": case "inactive": emailPreference = EmailPreference.NoMassEmails; break; default: emailPreference = EmailPreference.EmailAllowed; break; } person.EmailPreference = emailPreference; string primaryEmail = row[Email].Trim().Left( 75 ); if ( !string.IsNullOrWhiteSpace( primaryEmail ) ) { if ( primaryEmail.IsEmail() ) { person.Email = primaryEmail; person.IsEmailActive = isEmailActive; } else { LogException( "InvalidPrimaryEmail", string.Format( "PersonId: {0} - Email: {1}", rowPersonKey, primaryEmail ) ); } } string schoolName = row[School]; if ( !string.IsNullOrWhiteSpace( schoolName ) ) { // Add school if it doesn't exist Guid schoolGuid; var schoolExists = lookupContext.DefinedValues.Any( s => s.DefinedTypeId == schoolDefinedType.Id && s.Value.Equals( schoolName ) ); if ( !schoolExists ) { var newSchool = new DefinedValue(); newSchool.DefinedTypeId = schoolDefinedType.Id; newSchool.Value = schoolName; newSchool.Order = 0; lookupContext.DefinedValues.Add( newSchool ); lookupContext.SaveChanges(); schoolGuid = newSchool.Guid; } else { schoolGuid = lookupContext.DefinedValues.FirstOrDefault( s => s.Value.Equals( schoolName ) ).Guid; } AddPersonAttribute( schoolAttribute, person, schoolGuid.ToString().ToUpper() ); } foreach ( var attributePair in customAttributes ) { string newAttributeValue = row[attributePair.Key]; if ( !string.IsNullOrWhiteSpace( newAttributeValue ) ) { // check if this attribute value is a date DateTime valueAsDateTime; if ( DateTime.TryParseExact( newAttributeValue, dateFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, out valueAsDateTime ) ) { newAttributeValue = valueAsDateTime.ToString( "yyyy-MM-dd" ); } int? newAttributeId = personAttributes.Where( a => a.Key == attributePair.Value.RemoveWhitespace() ) .Select( a => (int?)a.Id ).FirstOrDefault(); if ( newAttributeId != null ) { var newAttribute = AttributeCache.Read( (int)newAttributeId ); AddPersonAttribute( newAttribute, person, newAttributeValue ); } } } // Add notes to timeline var notePairs = new Dictionary<string, string>(); notePairs.Add( "General", row[GeneralNote] ); notePairs.Add( "Medical", row[MedicalNote] ); notePairs.Add( "Security", row[SecurityNote] ); foreach ( var notePair in notePairs.Where( n => !string.IsNullOrWhiteSpace( n.Value ) ) ) { var newNote = new Note(); newNote.NoteTypeId = personalNoteTypeId; newNote.CreatedByPersonAliasId = ImportPersonAliasId; newNote.CreatedDateTime = ImportDateTime; newNote.Text = notePair.Value; newNote.ForeignKey = rowPersonKey; newNote.ForeignId = rowPersonId; newNote.Caption = string.Format( "{0} Note", notePair.Key ); if ( !notePair.Key.Equals( "General" ) ) { newNote.IsAlert = true; } newNoteList.Add( newNote ); } #endregion person create var groupMember = new GroupMember(); groupMember.Person = person; groupMember.GroupRoleId = groupRoleId; groupMember.CreatedDateTime = ImportDateTime; groupMember.ModifiedDateTime = ImportDateTime; groupMember.CreatedByPersonAliasId = ImportPersonAliasId; groupMember.GroupMemberStatus = GroupMemberStatus.Active; if ( rowFamilyKey != currentFamilyGroup.ForeignKey ) { // person not part of the previous family, see if that family exists or create a new one currentFamilyGroup = ImportedFamilies.FirstOrDefault( g => g.ForeignKey == rowFamilyKey ); if ( currentFamilyGroup == null ) { currentFamilyGroup = CreateFamilyGroup( row[FamilyName], rowFamilyKey ); newFamilyList.Add( currentFamilyGroup ); newFamilies++; } else { lookupContext.Groups.Attach( currentFamilyGroup ); lookupContext.Entry( currentFamilyGroup ).State = EntityState.Modified; } currentFamilyGroup.Members.Add( groupMember ); } else { // person is part of this family group, check if they're a visitor if ( isFamilyRelationship || currentFamilyGroup.Members.Count() < 1 ) { currentFamilyGroup.Members.Add( groupMember ); } else { var visitorFamily = CreateFamilyGroup( person.LastName + " Family", rowFamilyKey ); visitorFamily.Members.Add( groupMember ); newFamilyList.Add( visitorFamily ); newVisitorList.Add( visitorFamily ); newFamilies++; } } // look ahead 1 row string rowNextFamilyKey = "-1"; if ( (row = csvData.Database.FirstOrDefault()) != null ) { rowNextFamilyKey = row[FamilyId]; } newPeople++; completed++; if ( completed % (ReportingNumber * 10) < 1 ) { ReportProgress( 0, string.Format( "{0:N0} people imported.", completed ) ); } if ( newPeople >= ReportingNumber && rowNextFamilyKey != currentFamilyGroup.ForeignKey ) { SaveIndividuals( newFamilyList, newVisitorList, newNoteList ); lookupContext.SaveChanges(); ReportPartialProgress(); // Clear out variables currentFamilyGroup = new Group(); newFamilyList.Clear(); newVisitorList.Clear(); newNoteList.Clear(); newPeople = 0; } } else { row = csvData.Database.FirstOrDefault(); } } // Save any changes to new families if ( newFamilyList.Any() ) { SaveIndividuals( newFamilyList, newVisitorList, newNoteList ); } // Save any changes to existing families lookupContext.SaveChanges(); DetachAllInContext( lookupContext ); lookupContext.Dispose(); ReportProgress( 0, string.Format( "Finished individual import: {0:N0} families and {1:N0} people added.", newFamilies, completed ) ); return completed; }
/// <summary> /// Gets the entity fields. /// </summary> /// <param name="entityType">Type of the entity.</param> /// <param name="includeOnlyReportingFields">if set to <c>true</c> [include only reporting fields].</param> /// <returns></returns> public static List<EntityField> GetEntityFields( Type entityType, bool includeOnlyReportingFields = true ) { if ( _entityFields == null ) { _entityFields = new Dictionary<Type, List<EntityField>>(); } if ( _entityFields.ContainsKey( entityType ) && _entityFields[entityType] != null ) { return _entityFields[entityType]; } var entityFields = new List<EntityField>(); // Get Properties foreach ( var property in entityType.GetProperties() ) { if ( !property.GetGetMethod().IsVirtual || property.Name == "Id" || property.Name == "Guid" || property.Name == "Order" ) { EntityField entityProperty = null; // Enum Properties if ( property.PropertyType.IsEnum ) { entityProperty = new EntityField( property.Name, FieldKind.Property, property.PropertyType, 1 ); entityProperty.FilterFieldType = SystemGuid.FieldType.MULTI_SELECT; } // Boolean properties if ( property.PropertyType == typeof( bool ) || property.PropertyType == typeof( bool? ) ) { entityProperty = new EntityField( property.Name, FieldKind.Property, property.PropertyType, 1 ); entityProperty.FilterFieldType = SystemGuid.FieldType.SINGLE_SELECT; } // Date properties if ( property.PropertyType == typeof( DateTime ) || property.PropertyType == typeof( DateTime? ) ) { entityProperty = new EntityField( property.Name, FieldKind.Property, property.PropertyType, 2 ); entityProperty.FilterFieldType = SystemGuid.FieldType.DATE; } // Text Properties else if ( property.PropertyType == typeof( string ) ) { entityProperty = new EntityField( property.Name, FieldKind.Property, property.PropertyType, 2 ); entityProperty.FilterFieldType = SystemGuid.FieldType.TEXT; } // Integer Properties else if ( property.PropertyType == typeof( int ) || property.PropertyType == typeof( int? ) ) { var definedValueAttribute = property.GetCustomAttributes( typeof( Rock.Data.DefinedValueAttribute ), true ).FirstOrDefault(); if ( definedValueAttribute != null ) { // Defined Value Properties entityProperty = new EntityField( property.Name, FieldKind.Property, property.PropertyType, 1 ); var definedType = DefinedTypeCache.Read( ( (Rock.Data.DefinedValueAttribute)definedValueAttribute ).DefinedTypeGuid ); entityProperty.Title = definedType != null ? definedType.Name : property.Name.Replace( "ValueId", string.Empty ).SplitCase(); entityProperty.FilterFieldType = SystemGuid.FieldType.MULTI_SELECT; entityProperty.DefinedTypeGuid = definedType.Guid; } else { entityProperty = new EntityField( property.Name, FieldKind.Property, property.PropertyType, 2 ); entityProperty.FilterFieldType = SystemGuid.FieldType.INTEGER; } } if ( entityProperty != null ) { entityProperty.IsPreviewable = property.GetCustomAttributes( typeof( PreviewableAttribute ), true ).Any(); if ( includeOnlyReportingFields ) { bool isReportable = !property.GetCustomAttributes( typeof( HideFromReportingAttribute ), true ).Any(); if ( isReportable ) { entityFields.Add( entityProperty ); } } else { entityFields.Add( entityProperty ); } } } } // Get Attributes int entityTypeId = EntityTypeCache.Read( entityType ).Id; var rockContext = new RockContext(); var qryAttributes = new AttributeService( rockContext ).Queryable().Where( a => a.EntityTypeId == entityTypeId ); if ( entityType == typeof( Group ) ) { // in the case of Group, show attributes that are entity global, but also ones that are qualified by GroupTypeId qryAttributes = qryAttributes.Where( a => a.EntityTypeQualifierColumn == string.Empty || a.EntityTypeQualifierColumn == "GroupTypeId" ); } else { qryAttributes = qryAttributes.Where( a => a.EntityTypeQualifierColumn == string.Empty && a.EntityTypeQualifierValue == string.Empty ); } var attributeList = qryAttributes.ToList(); foreach ( var attribute in attributeList ) { AddEntityFieldForAttribute( entityFields, AttributeCache.Read( attribute.Id ) ); } int index = 1; _entityFields[entityType] = new List<EntityField>(); foreach ( var entityProperty in entityFields.OrderBy( p => p.Title ).ThenBy( p => p.Name ) ) { entityProperty.Index = index; index += entityProperty.ControlCount; _entityFields[entityType].Add( entityProperty ); } return _entityFields[entityType]; }
/// <summary> /// Loads the cache objects. /// </summary> private void LoadCacheObjects( RockContext rockContext ) { // Cache all the entity types foreach ( var entityType in new Rock.Model.EntityTypeService( rockContext ).Queryable().AsNoTracking() ) { EntityTypeCache.Read( entityType ); } // Cache all the Field Types foreach ( var fieldType in new Rock.Model.FieldTypeService( rockContext ).Queryable().AsNoTracking() ) { Rock.Web.Cache.FieldTypeCache.Read( fieldType ); } var all = Rock.Web.Cache.FieldTypeCache.All(); // Read all the qualifiers first so that EF doesn't perform a query for each attribute when it's cached var qualifiers = new Dictionary<int, Dictionary<string, string>>(); foreach ( var attributeQualifier in new Rock.Model.AttributeQualifierService( rockContext ).Queryable().AsNoTracking() ) { try { if ( !qualifiers.ContainsKey( attributeQualifier.AttributeId ) ) { qualifiers.Add( attributeQualifier.AttributeId, new Dictionary<string, string>() ); } qualifiers[attributeQualifier.AttributeId].Add( attributeQualifier.Key, attributeQualifier.Value ); } catch ( Exception ex ) { LogError( ex, null ); } } // Cache all the attributes, except for user preferences var attributeQuery = new Rock.Model.AttributeService( rockContext ).Queryable( "Categories" ); int? personUserValueEntityTypeId = Rock.Web.Cache.EntityTypeCache.GetId( Person.USER_VALUE_ENTITY ); if (personUserValueEntityTypeId.HasValue) { attributeQuery = attributeQuery.Where(a => !a.EntityTypeId.HasValue || a.EntityTypeId.Value != personUserValueEntityTypeId); } foreach ( var attribute in attributeQuery.AsNoTracking().ToList() ) { if ( qualifiers.ContainsKey( attribute.Id ) ) Rock.Web.Cache.AttributeCache.Read( attribute, qualifiers[attribute.Id] ); else Rock.Web.Cache.AttributeCache.Read( attribute, new Dictionary<string, string>() ); } // cache all the Country Defined Values since those can be loaded in just a few millisecond here, but take around 1-2 seconds if first loaded when formatting an address foreach ( var definedValue in new Rock.Model.DefinedValueService( rockContext ).GetByDefinedTypeGuid( Rock.SystemGuid.DefinedType.LOCATION_COUNTRIES.AsGuid() ).AsNoTracking() ) { DefinedValueCache.Read( definedValue, rockContext ); } }
/// <summary> /// Maps the communication data. /// </summary> /// <param name="tableData">The table data.</param> /// <returns></returns> private void MapCommunication( IQueryable<Row> tableData ) { var categoryService = new CategoryService(); var personService = new PersonService(); List<DefinedValue> numberTypeValues = new DefinedValueService().Queryable() .Where( dv => dv.DefinedType.Guid == new Guid( Rock.SystemGuid.DefinedType.PERSON_PHONE_TYPE ) ).ToList(); // Add a Social Media category if it doesn't exist int attributeEntityTypeId = EntityTypeCache.Read( "Rock.Model.Attribute" ).Id; int socialMediaCategoryId = categoryService.Queryable().Where( c => c.EntityType.Id == attributeEntityTypeId && c.Name == "Social Media" ).Select( c => c.Id ).FirstOrDefault(); if ( socialMediaCategoryId == 0 ) { var socialMediaCategory = new Category(); socialMediaCategory.IsSystem = false; socialMediaCategory.Name = "Social Media"; socialMediaCategory.IconCssClass = "fa fa-twitter"; socialMediaCategory.EntityTypeId = attributeEntityTypeId; socialMediaCategory.EntityTypeQualifierColumn = "EntityTypeId"; socialMediaCategory.EntityTypeQualifierValue = PersonEntityTypeId.ToString(); socialMediaCategory.Order = 0; categoryService.Add( socialMediaCategory, ImportPersonAlias ); categoryService.Save( socialMediaCategory, ImportPersonAlias ); socialMediaCategoryId = socialMediaCategory.Id; } int visitInfoCategoryId = categoryService.Queryable().Where( c => c.EntityTypeId == attributeEntityTypeId && c.Name == "Visit Information" ).Select( c => c.Id ).FirstOrDefault(); // Look up additional Person attributes (existing) var personAttributes = new AttributeService().GetByEntityTypeId( PersonEntityTypeId ).ToList(); // Add an Attribute for the secondary email int secondaryEmailAttributeId = personAttributes.Where( a => a.Key == "SecondaryEmail" ).Select( a => a.Id ).FirstOrDefault(); if ( secondaryEmailAttributeId == 0 ) { var newSecondaryEmailAttribute = new Rock.Model.Attribute(); newSecondaryEmailAttribute.Key = "SecondaryEmail"; newSecondaryEmailAttribute.Name = "Secondary Email"; newSecondaryEmailAttribute.FieldTypeId = TextFieldTypeId; newSecondaryEmailAttribute.EntityTypeId = PersonEntityTypeId; newSecondaryEmailAttribute.EntityTypeQualifierValue = string.Empty; newSecondaryEmailAttribute.EntityTypeQualifierColumn = string.Empty; newSecondaryEmailAttribute.Description = "The secondary email for this person"; newSecondaryEmailAttribute.DefaultValue = string.Empty; newSecondaryEmailAttribute.IsMultiValue = false; newSecondaryEmailAttribute.IsRequired = false; newSecondaryEmailAttribute.Order = 0; using ( new UnitOfWorkScope() ) { var attributeService = new AttributeService(); attributeService.Add( newSecondaryEmailAttribute ); var visitInfoCategory = new CategoryService().Get( visitInfoCategoryId ); newSecondaryEmailAttribute.Categories.Add( visitInfoCategory ); attributeService.Save( newSecondaryEmailAttribute ); secondaryEmailAttributeId = newSecondaryEmailAttribute.Id; } } // Add an Attribute for Twitter int twitterAttributeId = personAttributes.Where( a => a.Key == "TwitterUsername" ).Select( a => a.Id ).FirstOrDefault(); if ( twitterAttributeId == 0 ) { var newTwitterAttribute = new Rock.Model.Attribute(); newTwitterAttribute.Key = "TwitterUsername"; newTwitterAttribute.Name = "Twitter Username"; newTwitterAttribute.FieldTypeId = TextFieldTypeId; newTwitterAttribute.EntityTypeId = PersonEntityTypeId; newTwitterAttribute.EntityTypeQualifierValue = string.Empty; newTwitterAttribute.EntityTypeQualifierColumn = string.Empty; newTwitterAttribute.Description = "The Twitter username (or link) for this person"; newTwitterAttribute.DefaultValue = string.Empty; newTwitterAttribute.IsMultiValue = false; newTwitterAttribute.IsRequired = false; newTwitterAttribute.Order = 0; using ( new UnitOfWorkScope() ) { var attributeService = new AttributeService(); attributeService.Add( newTwitterAttribute ); var socialMediaCategory = new CategoryService().Get( socialMediaCategoryId ); newTwitterAttribute.Categories.Add( socialMediaCategory ); attributeService.Save( newTwitterAttribute ); twitterAttributeId = newTwitterAttribute.Id; } } // Add an Attribute for Facebook var facebookAttributeId = personAttributes.Where( a => a.Key == "FacebookUsername" ).Select( a => a.Id ).FirstOrDefault(); if ( facebookAttributeId == 0 ) { var newFacebookAttribute = new Rock.Model.Attribute(); newFacebookAttribute.Key = "FacebookUsername"; newFacebookAttribute.Name = "Facebook Username"; newFacebookAttribute.FieldTypeId = TextFieldTypeId; newFacebookAttribute.EntityTypeId = PersonEntityTypeId; newFacebookAttribute.EntityTypeQualifierValue = string.Empty; newFacebookAttribute.EntityTypeQualifierColumn = string.Empty; newFacebookAttribute.Description = "The Facebook username (or link) for this person"; newFacebookAttribute.DefaultValue = string.Empty; newFacebookAttribute.IsMultiValue = false; newFacebookAttribute.IsRequired = false; newFacebookAttribute.Order = 0; using ( new UnitOfWorkScope() ) { var attributeService = new AttributeService(); attributeService.Add( newFacebookAttribute ); var socialMediaCategory = new CategoryService().Get( socialMediaCategoryId ); newFacebookAttribute.Categories.Add( socialMediaCategory ); attributeService.Save( newFacebookAttribute ); facebookAttributeId = newFacebookAttribute.Id; } } var secondaryEmailAttribute = AttributeCache.Read( secondaryEmailAttributeId ); var twitterUsernameAttribute = AttributeCache.Read( twitterAttributeId ); var facebookUsernameAttribute = AttributeCache.Read( facebookAttributeId ); var existingNumbers = new PhoneNumberService().Queryable().ToList(); var newNumberList = new List<PhoneNumber>(); var updatedPersonList = new List<Person>(); int completed = 0; int totalRows = tableData.Count(); int percentage = ( totalRows - 1 ) / 100 + 1; ReportProgress( 0, string.Format( "Checking communication import ({0:N0} found).", totalRows ) ); foreach ( var row in tableData ) { string value = row["Communication_Value"] as string; int? individualId = row["Individual_ID"] as int?; int? householdId = row["Household_ID"] as int?; int? personId = GetPersonId( individualId, householdId ); if ( personId != null && !string.IsNullOrWhiteSpace( value ) ) { DateTime? lastUpdated = row["LastUpdatedDate"] as DateTime?; string communicationComment = row["Communication_Comment"] as string; string type = row["Communication_Type"] as string; bool isListed = (bool)row["Listed"]; if ( type.Contains( "Phone" ) || type.Contains( "Mobile" ) ) { var extension = string.Empty; int extensionIndex = value.LastIndexOf( 'x' ); if ( extensionIndex > 0 ) { extension = value.Substring( extensionIndex ).AsNumeric(); value = value.Substring( 0, extensionIndex ).AsNumeric(); } else { value = value.AsNumeric(); } if ( !string.IsNullOrWhiteSpace( value ) ) { bool numberExists = existingNumbers.Any( n => n.PersonId == (int)personId && n.Number.Equals( value ) ); if ( !numberExists ) { var newNumber = new PhoneNumber(); newNumber.CreatedByPersonAliasId = ImportPersonAlias.Id; newNumber.ModifiedDateTime = lastUpdated; newNumber.PersonId = (int)personId; newNumber.IsMessagingEnabled = false; newNumber.IsUnlisted = !isListed; newNumber.Extension = extension.Left( 20 ); newNumber.Number = value.Left( 20 ); newNumber.Description = communicationComment; newNumber.NumberTypeValueId = numberTypeValues.Where( v => type.StartsWith( v.Name ) ) .Select( v => (int?)v.Id ).FirstOrDefault(); newNumberList.Add( newNumber ); completed++; } } } else { var person = personService.Get( (int)personId ); person.Attributes = new Dictionary<string, AttributeCache>(); person.AttributeValues = new Dictionary<string, List<AttributeValue>>(); if ( value.IsValidEmail() ) { string secondaryEmail = string.Empty; if ( string.IsNullOrWhiteSpace( person.Email ) || ( isListed && person.IsEmailActive == false ) ) { secondaryEmail = person.Email; person.Email = value.Left( 75 ); person.IsEmailActive = isListed; person.DoNotEmail = !isListed; person.ModifiedDateTime = lastUpdated; person.EmailNote = communicationComment; } else if ( !person.Email.Equals( value ) ) { secondaryEmail = value; } if ( !string.IsNullOrWhiteSpace( secondaryEmail ) ) { person.Attributes.Add( "SecondaryEmail", secondaryEmailAttribute ); person.AttributeValues.Add( "SecondaryEmail", new List<AttributeValue>() ); person.AttributeValues["SecondaryEmail"].Add( new AttributeValue() { AttributeId = secondaryEmailAttribute.Id, Value = secondaryEmail, Order = 0 } ); } } else if ( type.Contains( "Twitter" ) ) { person.Attributes.Add( "TwitterUsername", twitterUsernameAttribute ); person.AttributeValues.Add( "TwitterUsername", new List<AttributeValue>() ); person.AttributeValues["TwitterUsername"].Add( new AttributeValue() { AttributeId = twitterUsernameAttribute.Id, Value = value, Order = 0 } ); } else if ( type.Contains( "Facebook" ) ) { person.Attributes.Add( "FacebookUsername", facebookUsernameAttribute ); person.AttributeValues.Add( "FacebookUsername", new List<AttributeValue>() ); person.AttributeValues["FacebookUsername"].Add( new AttributeValue() { AttributeId = facebookUsernameAttribute.Id, Value = value, Order = 0 } ); } updatedPersonList.Add( person ); completed++; } if ( completed % percentage < 1 ) { int percentComplete = completed / percentage; ReportProgress( percentComplete, string.Format( "{0:N0} records imported ({1}% complete).", completed, percentComplete ) ); } else if ( completed % ReportingNumber < 1 ) { RockTransactionScope.WrapTransaction( () => { var numberService = new PhoneNumberService(); numberService.RockContext.PhoneNumbers.AddRange( newNumberList ); numberService.RockContext.SaveChanges(); // don't add updatedPeople, they're already tracked with current context personService.RockContext.SaveChanges(); var attributeValueService = new AttributeValueService(); foreach ( var updatedPerson in updatedPersonList.Where( p => p.Attributes.Any() ) ) { foreach ( var attributeCache in updatedPerson.Attributes.Select( a => a.Value ) ) { var newValue = updatedPerson.AttributeValues[attributeCache.Key].FirstOrDefault(); if ( newValue != null ) { newValue.EntityId = updatedPerson.Id; attributeValueService.RockContext.AttributeValues.Add( newValue ); } } } attributeValueService.RockContext.SaveChanges(); } ); // reset the person context so it doesn't bloat if ( updatedPersonList.Any() ) { personService = new PersonService(); updatedPersonList.Clear(); } newNumberList.Clear(); ReportPartialProgress(); } } } RockTransactionScope.WrapTransaction( () => { var numberService = new PhoneNumberService(); numberService.RockContext.PhoneNumbers.AddRange( newNumberList ); numberService.RockContext.SaveChanges(); personService.RockContext.SaveChanges(); var attributeValueService = new AttributeValueService(); foreach ( var updatedPerson in updatedPersonList.Where( p => p.Attributes.Any() ) ) { foreach ( var attributeCache in updatedPerson.Attributes.Select( a => a.Value ) ) { var newValue = updatedPerson.AttributeValues[attributeCache.Key].FirstOrDefault(); if ( newValue != null ) { newValue.EntityId = updatedPerson.Id; attributeValueService.RockContext.AttributeValues.Add( newValue ); } } } attributeValueService.RockContext.SaveChanges(); } ); ReportProgress( 100, string.Format( "Finished communication import: {0:N0} records imported.", completed ) ); }
/// <summary> /// Loads the individual data. /// </summary> /// <param name="csvData">The CSV data.</param> private int LoadIndividuals( CsvDataModel csvData ) { var lookupContext = new RockContext(); var groupTypeRoleService = new GroupTypeRoleService( lookupContext ); var groupMemberService = new GroupMemberService( lookupContext ); // Marital statuses: Married, Single, Separated, etc var maritalStatusTypes = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.PERSON_MARITAL_STATUS ), lookupContext ).DefinedValues; // Connection statuses: Member, Visitor, Attendee, etc var connectionStatusTypes = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.PERSON_CONNECTION_STATUS ), lookupContext ).DefinedValues; int memberConnectionStatusId = connectionStatusTypes.FirstOrDefault( dv => dv.Guid == new Guid( Rock.SystemGuid.DefinedValue.PERSON_CONNECTION_STATUS_MEMBER ) ).Id; int visitorConnectionStatusId = connectionStatusTypes.FirstOrDefault( dv => dv.Guid == new Guid( Rock.SystemGuid.DefinedValue.PERSON_CONNECTION_STATUS_VISITOR ) ).Id; int attendeeConnectionStatusId = connectionStatusTypes.FirstOrDefault( dv => dv.Guid == new Guid( Rock.SystemGuid.DefinedValue.PERSON_CONNECTION_STATUS_ATTENDEE ) ).Id; // Suffix type: Dr., Jr., II, etc var suffixTypes = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.PERSON_SUFFIX ), lookupContext ).DefinedValues; // Title type: Mr., Mrs. Dr., etc var titleTypes = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.PERSON_TITLE ), lookupContext ).DefinedValues; // Record statuses: Active, Inactive, Pending int? recordStatusActiveId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_ACTIVE ), lookupContext ).Id; int? recordStatusInactiveId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_INACTIVE ), lookupContext ).Id; int? recordStatusPendingId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_PENDING ), lookupContext ).Id; // Deceased record status reason (others available: No Activity, Moved, etc) var recordStatusDeceasedId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_REASON_DECEASED ) ).Id; // Record type: Person int? personRecordTypeId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.PERSON_RECORD_TYPE_PERSON ), lookupContext ).Id; // Group roles: Owner, Adult, Child, others GroupTypeRole ownerRole = groupTypeRoleService.Get( new Guid( Rock.SystemGuid.GroupRole.GROUPROLE_KNOWN_RELATIONSHIPS_OWNER ) ); int adultRoleId = groupTypeRoleService.Get( new Guid( Rock.SystemGuid.GroupRole.GROUPROLE_FAMILY_MEMBER_ADULT ) ).Id; int childRoleId = groupTypeRoleService.Get( new Guid( Rock.SystemGuid.GroupRole.GROUPROLE_FAMILY_MEMBER_CHILD ) ).Id; // Phone types: Home, Work, Mobile var numberTypeValues = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.PERSON_PHONE_TYPE ), lookupContext ).DefinedValues; // Timeline note type id var noteTimelineTypeId = new NoteTypeService( lookupContext ).Get( new Guid( "7E53487C-D650-4D85-97E2-350EB8332763" ) ).Id; // School defined type var schoolDefinedType = DefinedTypeCache.Read( new Guid( "576FF1E2-6225-4565-A16D-230E26167A3D" ) ); // Look up additional Person attributes (existing) var personAttributes = new AttributeService( lookupContext ).GetByEntityTypeId( PersonEntityTypeId ).ToList(); // Core attributes: PreviousChurch, Position, Employer, School, etc var previousChurchAttribute = AttributeCache.Read( personAttributes.FirstOrDefault( a => a.Key == "PreviousChurch" ) ); var employerAttribute = AttributeCache.Read( personAttributes.FirstOrDefault( a => a.Key == "Employer" ) ); var positionAttribute = AttributeCache.Read( personAttributes.FirstOrDefault( a => a.Key == "Position" ) ); var firstVisitAttribute = AttributeCache.Read( personAttributes.FirstOrDefault( a => a.Key == "FirstVisit" ) ); var schoolAttribute = AttributeCache.Read( personAttributes.FirstOrDefault( a => a.Key == "School" ) ); var membershipDateAttribute = AttributeCache.Read( personAttributes.FirstOrDefault( a => a.Key == "MembershipDate" ) ); var baptismDateAttribute = AttributeCache.Read( personAttributes.FirstOrDefault( a => a.Key == "BaptismDate" ) ); var facebookAttribute = AttributeCache.Read( personAttributes.FirstOrDefault( a => a.Key == "Facebook" ) ); var twitterAttribute = AttributeCache.Read( personAttributes.FirstOrDefault( a => a.Key == "Twitter" ) ); var instagramAttribute = AttributeCache.Read( personAttributes.FirstOrDefault( a => a.Key == "Instagram" ) ); // Text field type id int textFieldTypeId = FieldTypeCache.Read( new Guid( Rock.SystemGuid.FieldType.TEXT ), lookupContext ).Id; // Attribute entity type id int attributeEntityTypeId = EntityTypeCache.Read( "Rock.Model.Attribute" ).Id; // Visit info category var visitInfoCategory = new CategoryService( lookupContext ).GetByEntityTypeId( attributeEntityTypeId ) .Where( c => c.Name == "Visit Information" ).FirstOrDefault(); // Add a Secondary Email attribute if it doesn't exist var secondaryEmail = personAttributes.FirstOrDefault( a => a.Key == "SecondaryEmail" ); if ( secondaryEmail == null ) { secondaryEmail = new Rock.Model.Attribute(); secondaryEmail.Key = "SecondaryEmail"; secondaryEmail.Name = "Secondary Email"; secondaryEmail.FieldTypeId = textFieldTypeId; secondaryEmail.EntityTypeId = PersonEntityTypeId; secondaryEmail.EntityTypeQualifierValue = string.Empty; secondaryEmail.EntityTypeQualifierColumn = string.Empty; secondaryEmail.Description = "The secondary email for this person"; secondaryEmail.DefaultValue = string.Empty; secondaryEmail.IsMultiValue = false; secondaryEmail.IsRequired = false; secondaryEmail.Order = 0; lookupContext.Attributes.Add( secondaryEmail ); secondaryEmail.Categories.Add( visitInfoCategory ); lookupContext.SaveChanges( true ); } var secondaryEmailAttribute = AttributeCache.Read( secondaryEmail.Id, lookupContext ); // Add a former name attribute var formerName = personAttributes.FirstOrDefault( a => a.Key == "FormerName" ); if ( formerName == null ) { formerName = new Rock.Model.Attribute(); formerName.Key = "FormerName"; formerName.Name = "Former Name"; formerName.FieldTypeId = textFieldTypeId; formerName.EntityTypeId = PersonEntityTypeId; formerName.EntityTypeQualifierValue = string.Empty; formerName.EntityTypeQualifierColumn = string.Empty; formerName.Description = "The former name for this person"; formerName.DefaultValue = string.Empty; formerName.IsMultiValue = false; formerName.IsRequired = false; formerName.Order = 0; lookupContext.Attributes.Add( formerName ); secondaryEmail.Categories.Add( visitInfoCategory ); lookupContext.SaveChanges( true ); } var formerNameAttribute = AttributeCache.Read( formerName.Id, lookupContext ); // Look for custom attributes in the Individual file var allFields = csvData.TableNodes.FirstOrDefault().Columns.Select( ( node, index ) => new { node = node, index = index } ).ToList(); Dictionary<int, string> customAttributes = allFields.Where( f => f.index > Twitter ).ToDictionary( f => f.index, f => f.node.Name ); // Add any if they don't already exist if ( customAttributes.Any() ) { var newAttributes = new List<Rock.Model.Attribute>(); foreach ( var newAttributePair in customAttributes.Where( ca => !personAttributes.Any( a => a.Name == ca.Value ) ) ) { var newAttribute = new Rock.Model.Attribute(); newAttribute.Name = newAttributePair.Value; newAttribute.Key = newAttributePair.Value.RemoveWhitespace(); newAttribute.Description = newAttributePair.Value + " created by CSV import"; newAttribute.EntityTypeQualifierValue = string.Empty; newAttribute.EntityTypeQualifierColumn = string.Empty; newAttribute.EntityTypeId = PersonEntityTypeId; newAttribute.FieldTypeId = textFieldTypeId; newAttribute.DefaultValue = string.Empty; newAttribute.IsMultiValue = false; newAttribute.IsGridColumn = false; newAttribute.IsRequired = false; newAttribute.Order = 0; newAttributes.Add( newAttribute ); } lookupContext.Attributes.AddRange( newAttributes ); lookupContext.SaveChanges( true ); personAttributes.AddRange( newAttributes ); } var dateFormats = new[] { "MM/dd/yyyy", "MM/dd/yy" }; var currentFamilyGroup = new Group(); var newFamilyList = new List<Group>(); var newVisitorList = new List<Group>(); var importDate = DateTime.Now; int completed = 0; ReportProgress( 0, string.Format( "Starting Individual import ({0:N0} already exist).", ImportedPeople.Count( p => p.Members.Any( m => m.Person.ForeignId != null ) ) ) ); string[] row; // Uses a look-ahead enumerator: this call will move to the next record immediately while ( ( row = csvData.Database.FirstOrDefault() ) != null ) { int groupRoleId = adultRoleId; bool isFamilyRelationship = true; string rowFamilyId = row[FamilyId]; string rowPersonId = row[PersonId]; string rowFamilyName = row[FamilyName]; if ( !string.IsNullOrWhiteSpace( rowFamilyId ) && rowFamilyId != currentFamilyGroup.ForeignId ) { currentFamilyGroup = ImportedPeople.FirstOrDefault( p => p.ForeignId == rowFamilyId ); if ( currentFamilyGroup == null ) { currentFamilyGroup = new Group(); currentFamilyGroup.ForeignId = rowFamilyId; currentFamilyGroup.Name = row[FamilyName]; currentFamilyGroup.CreatedByPersonAliasId = ImportPersonAlias.Id; currentFamilyGroup.GroupTypeId = FamilyGroupTypeId; } } // Verify this person isn't already in our data var personExists = ImportedPeople.Any( p => p.Members.Any( m => m.Person.ForeignId == rowPersonId ) ); if ( !personExists ) { var person = new Person(); person.ForeignId = rowPersonId; person.SystemNote = string.Format( "Imported via Excavator on {0}", importDate.ToString() ); person.RecordTypeValueId = personRecordTypeId; person.CreatedByPersonAliasId = ImportPersonAlias.Id; string firstName = row[FirstName]; person.FirstName = firstName; person.NickName = row[NickName] ?? firstName; person.MiddleName = row[MiddleName]; person.LastName = row[LastName]; #region Assign values to the Person record DateTime birthDate; if ( DateTime.TryParseExact( row[DateOfBirth], dateFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, out birthDate ) ) { person.BirthDate = birthDate; } DateTime anniversary; if ( DateTime.TryParseExact( row[Anniversary], dateFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, out anniversary ) ) { person.AnniversaryDate = anniversary; } string gender = row[Gender]; if ( gender != null ) { switch ( gender.Trim().ToLower() ) { case "m": case "male": person.Gender = Rock.Model.Gender.Male; break; case "f": case "female": person.Gender = Rock.Model.Gender.Female; break; default: person.Gender = Rock.Model.Gender.Unknown; break; } } string prefix = row[Prefix]; if ( !string.IsNullOrWhiteSpace( prefix ) ) { prefix = prefix.RemoveSpecialCharacters().Trim(); person.TitleValueId = titleTypes.Where( s => prefix == s.Value.RemoveSpecialCharacters() ) .Select( s => (int?)s.Id ).FirstOrDefault(); } string suffix = row[Suffix]; if ( !string.IsNullOrWhiteSpace( suffix ) ) { suffix = suffix.RemoveSpecialCharacters().Trim(); person.SuffixValueId = suffixTypes.Where( s => suffix == s.Value.RemoveSpecialCharacters() ) .Select( s => (int?)s.Id ).FirstOrDefault(); } string maritalStatus = row[MaritalStatus]; if ( !string.IsNullOrWhiteSpace( maritalStatus ) ) { person.MaritalStatusValueId = maritalStatusTypes.Where( dv => dv.Value == maritalStatus ) .Select( dv => (int?)dv.Id ).FirstOrDefault(); } else { person.MaritalStatusValueId = maritalStatusTypes.Where( dv => dv.Value == "Unknown" ) .Select( dv => (int?)dv.Id ).FirstOrDefault(); } string familyRole = row[FamilyRole]; if ( !string.IsNullOrWhiteSpace( familyRole ) ) { if ( familyRole == "Visitor" ) { isFamilyRelationship = false; } if ( familyRole == "Child" || person.Age < 18 ) { groupRoleId = childRoleId; } } string connectionStatus = row[ConnectionStatus]; if ( !string.IsNullOrWhiteSpace( connectionStatus ) ) { if ( connectionStatus == "Member" ) { person.ConnectionStatusValueId = memberConnectionStatusId; } else if ( connectionStatus == "Visitor" ) { person.ConnectionStatusValueId = visitorConnectionStatusId; } else if ( connectionStatus == "Deceased" ) { person.IsDeceased = true; person.RecordStatusReasonValueId = recordStatusDeceasedId; } else { // look for user-defined connection type or default to Attendee var customConnectionType = connectionStatusTypes.Where( dv => dv.Value == connectionStatus ) .Select( dv => (int?)dv.Id ).FirstOrDefault(); person.ConnectionStatusValueId = customConnectionType ?? attendeeConnectionStatusId; person.RecordStatusValueId = recordStatusActiveId; } } string recordStatus = row[RecordStatus]; if ( !string.IsNullOrWhiteSpace( recordStatus ) ) { switch ( recordStatus.Trim() ) { case "Active": person.RecordStatusValueId = recordStatusActiveId; break; case "Inactive": person.RecordStatusValueId = recordStatusInactiveId; break; default: person.RecordStatusValueId = recordStatusPendingId; break; } } var personNumbers = new Dictionary<string, string>(); personNumbers.Add( "Home", row[HomePhone] ); personNumbers.Add( "Mobile", row[MobilePhone] ); personNumbers.Add( "Work", row[WorkPhone] ); string smsAllowed = row[AllowSMS]; foreach ( var numberPair in personNumbers.Where( n => !string.IsNullOrWhiteSpace( n.Value ) ) ) { var extension = string.Empty; var countryCode = Rock.Model.PhoneNumber.DefaultCountryCode(); var normalizedNumber = string.Empty; var countryIndex = numberPair.Value.IndexOf( '+' ); int extensionIndex = numberPair.Value.LastIndexOf( 'x' ) > 0 ? numberPair.Value.LastIndexOf( 'x' ) : numberPair.Value.Length; if ( countryIndex >= 0 ) { countryCode = numberPair.Value.Substring( countryIndex, countryIndex + 3 ).AsNumeric(); normalizedNumber = numberPair.Value.Substring( countryIndex + 3, extensionIndex - 3 ).AsNumeric(); extension = numberPair.Value.Substring( extensionIndex ); } else if ( extensionIndex > 0 ) { normalizedNumber = numberPair.Value.Substring( 0, extensionIndex ).AsNumeric(); extension = numberPair.Value.Substring( extensionIndex ).AsNumeric(); } else { normalizedNumber = numberPair.Value.AsNumeric(); } if ( !string.IsNullOrWhiteSpace( normalizedNumber ) ) { var currentNumber = new PhoneNumber(); currentNumber.CountryCode = countryCode; currentNumber.CreatedByPersonAliasId = ImportPersonAlias.Id; currentNumber.Extension = extension.Left( 20 ); currentNumber.Number = normalizedNumber.Left( 20 ); currentNumber.NumberTypeValueId = numberTypeValues.Where( v => v.Value.Equals( numberPair.Key ) ) .Select( v => (int?)v.Id ).FirstOrDefault(); if ( numberPair.Key == "Mobile" ) { switch ( smsAllowed.Trim().ToLower() ) { case "y": case "yes": case "active": currentNumber.IsMessagingEnabled = true; break; default: currentNumber.IsMessagingEnabled = false; break; } } person.PhoneNumbers.Add( currentNumber ); } } // Map Person attributes person.Attributes = new Dictionary<string, AttributeCache>(); person.AttributeValues = new Dictionary<string, AttributeValue>(); string formerNameValue = row[FormerName]; if ( !string.IsNullOrWhiteSpace( formerNameValue ) ) { AddPersonAttribute( formerNameAttribute, person, formerNameValue ); } bool isEmailActive; switch ( row[IsEmailActive].Trim().ToLower() ) { case "n": case "no": case "inactive": isEmailActive = false; break; default: isEmailActive = true; break; } EmailPreference emailPreference; switch ( row[AllowBulkEmail].Trim().ToLower() ) { case "n": case "no": case "inactive": emailPreference = EmailPreference.NoMassEmails; break; default: emailPreference = EmailPreference.EmailAllowed; break; } string primaryEmail = row[Email]; if ( !string.IsNullOrWhiteSpace( primaryEmail ) ) { person.Email = primaryEmail; person.IsEmailActive = isEmailActive; person.EmailPreference = emailPreference; } string secondaryEmailValue = row[SecondaryEmail]; if ( !string.IsNullOrWhiteSpace( secondaryEmailValue ) ) { AddPersonAttribute( secondaryEmailAttribute, person, secondaryEmailValue ); } DateTime membershipDateValue; if ( DateTime.TryParseExact( row[MembershipDate], dateFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, out membershipDateValue ) ) { AddPersonAttribute( membershipDateAttribute, person, membershipDateValue.ToString() ); } DateTime baptismDateValue; if ( DateTime.TryParseExact( row[BaptismDate], dateFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, out baptismDateValue ) ) { AddPersonAttribute( baptismDateAttribute, person, baptismDateValue.ToString() ); } DateTime firstVisitValue; if ( DateTime.TryParseExact( row[FirstVisit], dateFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, out firstVisitValue ) ) { AddPersonAttribute( firstVisitAttribute, person, firstVisitValue.ToString() ); } string previousChurchValue = row[PreviousChurch]; if ( !string.IsNullOrWhiteSpace( previousChurchValue ) ) { AddPersonAttribute( previousChurchAttribute, person, previousChurchValue ); } string positionValue = row[Occupation]; if ( !string.IsNullOrWhiteSpace( positionValue ) ) { AddPersonAttribute( positionAttribute, person, positionValue ); } string employerValue = row[Employer]; if ( !string.IsNullOrWhiteSpace( employerValue ) ) { AddPersonAttribute( employerAttribute, person, employerValue ); } string schoolName = row[School]; if ( !string.IsNullOrWhiteSpace( schoolName ) ) { // Add school if it doesn't exist Guid schoolGuid; var schoolExists = schoolDefinedType.DefinedValues.Any( s => s.Value.Equals( schoolName ) ); if ( !schoolExists ) { var newSchool = new DefinedValue(); newSchool.DefinedTypeId = schoolDefinedType.Id; newSchool.Value = schoolName; newSchool.Order = 0; lookupContext.DefinedValues.Add( newSchool ); lookupContext.SaveChanges(); schoolGuid = newSchool.Guid; } else { schoolGuid = schoolDefinedType.DefinedValues.FirstOrDefault( s => s.Value.Equals( schoolName ) ).Guid; } AddPersonAttribute( schoolAttribute, person, schoolGuid.ToString() ); } string facebookValue = row[Facebook]; if ( !string.IsNullOrWhiteSpace( facebookValue ) ) { AddPersonAttribute( facebookAttribute, person, facebookValue ); } string twitterValue = row[Twitter]; if ( !string.IsNullOrWhiteSpace( twitterValue ) ) { AddPersonAttribute( twitterAttribute, person, twitterValue ); } string instagramValue = row[Instagram]; if ( !string.IsNullOrWhiteSpace( instagramValue ) ) { AddPersonAttribute( instagramAttribute, person, instagramValue ); } foreach ( var attributePair in customAttributes ) { string newAttributeValue = row[attributePair.Key]; if ( !string.IsNullOrWhiteSpace( newAttributeValue ) ) { int? newAttributeId = personAttributes.Where( a => a.Key == attributePair.Value ) .Select( a => (int?)a.Id ).FirstOrDefault(); if ( newAttributeId != null ) { var newAttribute = AttributeCache.Read( (int)newAttributeId ); AddPersonAttribute( newAttribute, person, newAttributeValue ); } } } // Add notes to timeline var notePairs = new Dictionary<string, string>(); notePairs.Add( "General", row[GeneralNote] ); notePairs.Add( "Medical", row[MedicalNote] ); notePairs.Add( "Security", row[SecurityNote] ); var newNoteList = new List<Note>(); foreach ( var notePair in notePairs.Where( n => !string.IsNullOrWhiteSpace( n.Value ) ) ) { var newNote = new Note(); newNote.CreatedByPersonAliasId = ImportPersonAlias.Id; newNote.CreatedDateTime = importDate; newNote.EntityId = person.Id; newNote.Text = notePair.Value; newNote.NoteTypeId = noteTimelineTypeId; newNote.Caption = string.Format( "{0} Note", notePair.Key ); if ( !notePair.Key.Equals( "General" ) ) { newNote.IsAlert = true; } newNoteList.Add( newNote ); } if ( newNoteList.Any() ) { lookupContext.Notes.AddRange( newNoteList ); lookupContext.SaveChanges( true ); } #endregion var groupMember = new GroupMember(); groupMember.Person = person; groupMember.GroupRoleId = groupRoleId; groupMember.GroupMemberStatus = GroupMemberStatus.Active; if ( isFamilyRelationship || currentFamilyGroup.Members.Count() < 1 ) { currentFamilyGroup.Members.Add( groupMember ); newFamilyList.Add( currentFamilyGroup ); completed++; } else { var visitorGroup = new Group(); visitorGroup.ForeignId = rowFamilyId.ToString(); visitorGroup.Members.Add( groupMember ); visitorGroup.GroupTypeId = FamilyGroupTypeId; visitorGroup.Name = person.LastName + " Family"; newFamilyList.Add( visitorGroup ); completed++; newVisitorList.Add( visitorGroup ); } if ( completed % ( ReportingNumber * 10 ) < 1 ) { ReportProgress( 0, string.Format( "{0:N0} people imported.", completed ) ); } else if ( completed % ReportingNumber < 1 ) { SaveIndividuals( newFamilyList, newVisitorList ); ReportPartialProgress(); newFamilyList.Clear(); } } } if ( newFamilyList.Any() ) { SaveIndividuals( newFamilyList, newVisitorList ); } ReportProgress( 0, string.Format( "Finished individual import: {0:N0} people imported.", completed ) ); return completed; }