[NOTE: This is a development environment tool only! It’s meant to greatly simpilfy the initial create entity process for developers.]{.lead}
One annoying thing about meta-based systems is that some times you need to enter a lot of data for things that seem simple. With Aptify it’s Entities as the UI interface isn’t designed for speed entry. So when you need to create multiple entities for a project it can be a big pain.
As I do a lot of create, wipe the DB and re-create/modify this was getting super annoying. Yes, anyone who know Aptify I could have packed up the Entities and un-packed them… but I didn’t because I was always changing things, haha.
One day I was fiddling with dbdiagram.io and tried it’s export feature which gives you the raw create table statements for multiple DB types. Then I had it, why couldn’t I have something like this for Aptify Entities? I could easily plan out my entities in my own structured content and then just run that through a parser that would create the entities.
For the structured content I chose Yaml. I’d wanting to play around with it more and as I started a rough draft I fell in love with Yaml. JSON your awesome when I’m not physically typing you out, haha. If I’m typing it out, I think Yaml is king now.
Ok, we have Yaml structure now we need a parser. For that I chose a .Net Framework 4.8 Console Application (note: Aptify 7 is still on Framework 4.8). Added in all the bits I needed, add a bunch of my own opinionated entity best practices not only to standardize it but also make the Yaml as simple to type as possible. Things like:
- Entity name and Table name are singular
- Display name and Base view are plural
- Auto Prepend or Suffix org code
- Add linked joined fields but just specifying the field names
- Maintain order of fields
- Auto create or add entities to applications
- Subtype parent entity ID name fix so instead of Enity_orgID you get EntityID_org
It also has the basic concept of field templates. For example when you need to create a new Type style entity which using is just Name and Description, I didn’t want to write that every single time so, templates.
Example
Here is the Yaml for my AMFA project. It’s roughly 57 entities and it takes roughly 3 min to fully process! To do this manually would probably be also 2 hours.
// VIDEO EXAMPLE COMING SOON //
prefix: null
suffix: _amfa
applicationEntities:
mode: all
name: Anime/Manga Fans Association_amfa
display: _ AMFA _
entities:
# STAND-ALONE START
- name: PersonAnimeMangaType
display: Person Anime/Manga Types
baseView: PersonAnimeMangaTypes
template: Amfa Type Table
- name: PersonAnimeMangaStatus
display: Person Anime/Manga Statuses
template: Amfa Type Table
- name: CompanyType
template: Amfa Type Table
- name: Country
fields:
- name: Name
sqlFieldSize: 100
isRequired: true
- name: IsoCode
sqlFieldSize: 3
isRequired: true
- name: Genre
template: Amfa Type Table
- name: AnimeSource
template: Amfa Type Table
- name: AnimeMediaRating
template: Amfa Type Table
- name: AnimeMangaMediaType
display: Anime/Manga Media Types
template: Amfa Type Table
- name: AnimeMangaRelationType
display: Anime/Manga Relation Types
template: Amfa Type Table
- name: AnimeMangaReleaseStatus
display: Anime/Manga Release Statuses
template: Amfa Type Table
- name: ForumCategory
template: Amfa Type Table
- name: ForumPostLevel
template: Amfa Type Table
- name: GroupType
template: Amfa Type Table
- name: GroupTermMemberRole
template: Amfa Type Table
- name: AnimeMangaRelationType
display: Anime/Manga Relation Types
template: Amfa Type Table
- name: EventType
template: Amfa Type Table
- name: JobCategory
template: Amfa Type Table
- name: JobType
template: Amfa Type Table
- name: JobCareerLevel
template: Amfa Type Table
- name: JobWageType
template: Amfa Type Table
- name: JobExperienceLevel
template: Amfa Type Table
- name: CourseLevel
template: Amfa Type Table
- name: CourseCategory
template: Amfa Type Table
- name: CourseModulePartType
template: Amfa Type Table
- name: ProductCategory
template: Amfa Type Table
- name: ProductType
template: Amfa Type Table
- name: ProductAvailableType
template: Amfa Type Table
- name: ProductQualityLevel
template: Amfa Type Table
- name: Person
fields:
- name: Email
sqlFieldSize: 250
isRequired: true
isUnique: true
- name: FirstLast
calcCompType: Computed
calcCompSql: "RTRIM(FirstName) + ' ' + LTRIM(LastName)"
- name: LastName
sqlFieldSize: 25
isRequired: true
- name: FirstName
sqlFieldSize: 25
isRequired: true
- name: MalUsername
sqlFieldSize: 150
- name: AvatarUrl
sqlFieldSize: 500
- name: Bio
sqlFieldSize: 1000
- name: Company
fields:
- name: Name
sqlFieldSize: 250
isRequired: true
- name: CompanyTypeID
linkedEntity: CompanyType_amfa
isRequired: true
joinedFields:
- joinedField: Name
- name: CountryID
linkedEntity: Country_amfa
isRequired: true
joinedFields:
- joinedField: Name
- name: Description
sqlFieldSize: 4000
- name: Directions
sqlFieldSize: 500
- name: MapLink
sqlFieldSize: 250
- name: Website
sqlFieldSize: 250
# STAND-ALONE END
# ANIME/MANGA START
- name: AnimeManga
display: Anime/Manga
baseView: AnimeManga
fields:
- name: ReferenceId
display: Reference Id
isRequired: true
sqlFieldSize: 25
isUnique: true
- name: Type
values:
- Anime
- Manga
isRequired: true
- name: Title
sqlFieldSize: 150
isRequired: true
- name: MediaTypeID
linkedEntity: AnimeMangaMediaType_amfa
isRequired: true
- name: ReleaseStatusID
linkedEntity: AnimeMangaReleaseStatus_amfa
isRequired: true
- name: Description
sqlFieldSize: 500
- name: StartDate
sqlDataType: date
- name: EndDate
sqlDataType: date
- name: SyncDate
sqlDataType: datetime
- name: CoverImageUrl
sqlFieldSize: 500
- name: BannerUrl
sqlFieldSize: 500
- name: Nsfw
values:
- white
- gray
- black
default: white
- name: EpisodesChapters
sqlDataType: int
- name: AnimeSourceId
linkedEntity: AnimeSource_amfa
- name: MediaRatingId
linkedEntity: AnimeMediaRating_amfa
- name: AnimeYear
sqlDataType: int
- name: AnimeSeason
sqlFieldSize: 6
values:
- Winter
- Spring
- Summer
- Fall
- name: AnimeEpAvgDuration
sqlDataType: int
- name: AnimeBroadcastDayOfWeek
sqlFieldSize: 10
values:
- Sunday
- Monday
- Tuesday
- Wednesday
- Thursday
- Friday
- Saturday
- name: MangaVolumes
sqlDataType: int
- name: AnimeMangaSynonym
display: Synonyms
parent: AnimeManga_amfa
fields:
- name: Synonym
isRequired: true
- name: AnimeMangaRelation
display: Relations
parent: AnimeManga_amfa
fields:
- name: RelatedID
linkedEntity: AnimeManga_amfa
isRequired: true
- name: RelationTypeID
linkedEntity: AnimeMangaRelationType_amfa
isRequired: true
- name: AnimeMangaStudio
display: Studios
parent: AnimeManga_amfa
fields:
- name: CompanyID
linkedEntity: Company_amfa
isRequired: true
- name: AnimeMangaGenre
display: Genres
parent: AnimeManga_amfa
fields:
- name: GenreID
linkedEntity: Genre_amfa
isRequired: true
- name: PersonAnimeManga
display: Anime/Manga
parent: Person_amfa
fields:
- name: AnimeMangaID
linkedEntity: AnimeManga_amfa
isRequired: true
- name: TypeID
linkedEntity: PersonAnimeMangaType_amfa
isRequired: true
- name: StatusID
linkedEntity: PersonAnimeMangaStatus_amfa
isRequired: true
- name: Progression
sqlDataType: int
isRequired: true
- name: Rating
sqlDataType: int
values: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
- name: IsRe
sqlDataType: bit
# ANIME/MANGA END
# FORUMS START
- name: Forum
fields:
- name: Name
isRequired: true
isUnique: true
- name: Description
sqlFieldSize: 500
isRequired: true
- name: CategoryID
linkedEntity: ForumCategory_amfa
isRequired: true
- name: PostLevelID
linkedEntity: ForumPostLevel_amfa
isRequired: true
- name: StartDate
sqlDataType: date
isRequired: true
- name: EndDate
sqlDataType: date
- name: ThumbnailUrl
sqlFieldSize: 500
- name: BannerUrl
sqlFieldSize: 500
- name: ForumModerator
display: Moderators
parent: Forum_amfa
fields:
- name: PersonID
linkedEntity: Persons_amfa
isRequired: true
- name: ForumPost
display: Posts
parent: Forum_amfa
fields:
- name: PersonID
linkedEntity: Persons_amfa
isRequired: true
- name: ParentID
linkedEntity: this
- name: Subject
sqlFieldSize: 250
isRequired: true
- name: Post
sqlFieldSize: 500
isRequired: true
- name: ForumPostWatcher
display: Watchers
parent: Forum_amfa
fields:
- name: PersonID
linkedEntity: Persons_amfa
isRequired: true
- name: StartDate
sqlDataType: datetime
isRequired: true
- name: EndDate
sqlDataType: datetime
- name: ForumPinnedPost
display: Pinned Posts
parent: Forum_amfa
fields:
- name: StartDate
sqlDataType: datetime
isRequired: true
- name: EndDate
sqlDataType: datetime
# FORUMS END
# COUSES START
- name: Course
fields:
- name: Title
sqlFieldSize: 250
isRequired: true
- name: ProductID
linkedEntity: Products_amfa
- name: CategoryID
linkedEntity: CourseCategory_amfa
isRequired: true
- name: LevelID
linkedEntity: CourseLevel_amfa
- name: Summary
sqlFieldSize: 500
isRequired: true
- name: Description
sqlFieldSize: 500
- name: ContentInfo
sqlFieldSize: 500
- name: WhatYouLearn
sqlFieldSize: 500
- name: Rating
sqlDataType: decimal
sqlDecimalPrecisionLength: 6
sqlDecimalPrecisionPoints: 2
- name: ThumbnailUrl
sqlFieldSize: 500
- name: CourseGenre
display: Genres
parent: Course_amfa
fields:
- name: GenreID
linkedEntity: Genre_amfa
isRequired: true
- name: CourseInstructor
display: Instructors
parent: Course_amfa
fields:
- name: PersonID
linkedEntity: Person_amfa
isRequired: true
- name: StartDate
sqlDataType: date
isRequired: true
- name: EndDate
sqlDataType: date
- name: CourseImage
display: Images
parent: Course_amfa
fields:
- name: Url
sqlFieldSize: 500
isRequired: true
- name: Ordinal
sqlDataType: int
default: 100
- name: CourseOffering
display: Offerings
parent: Course_amfa
fields:
- name: StartDate
sqlDataType: date
isRequired: true
- name: EndDate
sqlDataType: date
- name: CourseReview
display: Reviews
parent: Course_amfa
fields:
- name: PersonID
linkedEntity: Person_amfa
isRequired: true
- name: Review
sqlFieldSize: 500
isRequired: true
- name: Rating
sqlDataType: decimal
sqlDecimalPrecisionLength: 6
sqlDecimalPrecisionPoints: 2
isRequired: true
- name: SubmittedDate
sqlDataType: datetime
isRequired: true
- name: CourseModule
display: Modules
parent: Course_amfa
fields:
- name: Title
sqlFieldSize: 250
isRequired: true
- name: CourseModulePart
display: Parts
parent: CourseModule_amfa
fields:
- name: Title
sqlFieldSize: 250
isRequired: true
- name: TypeID
linkedEntity: CourseModulePartType_amfa
isRequired: true
- name: Description
sqlFieldSize: 500
- name: ContentLengthSeconds
sqlDataType: int
# COURSES END
# EVENTS START
- name: EventOrganizer
fields:
- name: Name
sqlFieldSize: 150
isRequired: true
- name: Description
sqlFieldSize: 500
- name: LogoUrl
sqlFieldSize: 250
- name: Website
sqlFieldSize: 250
- name: Event
fields:
- name: Title
sqlFieldSize: 150
isRequired: true
- name: TypeID
linkedEntity: EventType_amfa
- name: Description
sqlFieldSize: 500
isRequired: true
- name: VenueID
linkedEntity: Company_amfa
allowNull: true
- name: StartDate
sqlDataType: datetime
isRequired: true
- name: EndDate
sqlDataType: datetime
- name: OrganizerID
linkedEntity: EventOrganizer_amfa
- name: LogoUrl
sqlFieldSize: 250
- name: RegistrationUrl
sqlFieldSize: 250
# EVENTS END
# JOBS START
- name: Job
fields:
- name: Title
sqlFieldSize: 150
isRequired: true
- name: CategoryID
linkedEntity: JobCategory_amfa
isRequired: true
- name: TypeID
linkedEntity: JobType_amfa
isRequired: true
- name: CareerLevelID
linkedEntity: JobCareerLevel_amfa
isRequired: true
- name: WageTypeID
linkedEntity: JobWageType_amfa
isRequired: true
- name: ExperienceLevelID
linkedEntity: JobExperienceLevel_amfa
isRequired: true
- name: CompanyID
linkedEntity: Company_amfa
isRequired: true
- name: CountryID
linkedEntity: Country_amfa
isRequired: true
- name: City
sqlFieldSize: 150
isRequired: true
- name: StateProvince
sqlFieldSize: 150
- name: PostalCode
sqlFieldSize: 15
isRequired: true
- name: AllowRemote
sqlDataType: bit
- name: WageMin
sqlDataType: money
isRequired: true
- name: WageMax
sqlDataType: money
isRequired: true
- name: DateCreated
sqlDataType: datetime
isRequired: true
- name: Description
sqlFieldSize: 2000
isRequired: true
- name: JobPosting
fields:
- name: JobID
linkedEntity: Job_amfa
isRequired: true
- name: StartDate
sqlDataType: datetime
isRequired: true
- name: EndDate
sqlDataType: datetime
# JOBS END
# PRODUCTS START
- name: Product
description: These are the products we sell
fields:
- name: Title
sqlFieldSize: 150
isRequired: true
isNameField: true
- name: Description
sqlFieldSize: 500
- name: CategoryID
display: Category
linkedEntity: ProductCategory_amfa
isRequired: true
joinedFields:
- joinedField: Name
- name: ProductTypeID
display: Product Type
linkedEntity: ProductType_amfa
isRequired: true
joinedFields:
- joinedField: Name
- name: AvailableID
display: Availability
linkedEntity: ProductAvailableType_amfa
joinedFields:
- joinedField: Name
- name: QualityLevelID
display: Quality
linkedEntity: ProductQualityLevel_amfa
joinedFields:
- joinedField: Name
- name: Price
sqlDataType: decimal
sqlDecimalPrecisionLength: 8
sqlDecimalPrecisionPoints: 2
- name: ReleaseDate
sqlDataType: datetime
- name: Weight
sqlDataType: decimal
sqlDecimalPrecisionLength: 8
sqlDecimalPrecisionPoints: 2
- name: Width
sqlDataType: decimal
sqlDecimalPrecisionLength: 8
sqlDecimalPrecisionPoints: 2
- name: Height
sqlDataType: decimal
sqlDecimalPrecisionLength: 8
sqlDecimalPrecisionPoints: 2
- name: PackageWeight
sqlDataType: decimal
sqlDecimalPrecisionLength: 8
sqlDecimalPrecisionPoints: 2
- name: PackageWidth
sqlDataType: decimal
sqlDecimalPrecisionLength: 8
sqlDecimalPrecisionPoints: 2
- name: PackageHeight
sqlDataType: decimal
sqlDecimalPrecisionLength: 8
sqlDecimalPrecisionPoints: 2
- name: AnimeMangaID
display: Anime/Manga
linkedEntity: AnimeManga_amfa
joinedFields:
- joinedField: Title
- name: ProductImages
parent: Product_amfa
fields:
- name: Name
isRequired: true
isNameField: true
- name: Url
isRequired: true
sqlFieldSize: 250
- name: Ordinal
isRequired: true
sqlDataType: int
default: 100
- name: ProductGenre
parent: Product_amfa
fields:
- name: GenreID
linkedEntity: Genre_amfa
isRequired: true
joinedFields:
- joinedField: Name
isNameField: true
- name: ProductAttribute
parent: Product_amfa
fields:
- name: Name
sqlFieldSize: 250
isRequired: true
isNameField: true
- name: Value
sqlFieldSize: 500
# PRODUCTS END