NOTE: Apart from
(and even then it's questionable, I'm Scottish). These are machine translated in languages I don't read. If they're terrible please contact me.
You can see how this translation was done in this article.
Saturday, 17 August 2024
//Less than a minute
Katso osat 1 sekä 2 sekä 3 edellisten vaiheiden osalta.
Aiemmissa osissa selvitimme, miten tietokanta perustetaan, miten ohjaimemme ja näkemyksemme rakentuvat ja miten palvelumme toimivat. Tässä osassa kerromme yksityiskohtaisesti, miten tietokantaan voi upottaa alkutietoja ja miten EF-pohjaiset palvelut toimivat.
Kuten tavallista, näet kaiken tämän lähteen GitHubistani. täällä, Enimmäkseen lucid/Blog-kansiossa.
[TÄYTÄNTÖÖNPANO
Edellisessä osassa kerroimme, miten Alusta ja perusta palvelut...................................................................................................................................... Tässä osassa käsittelemme, miten tietokantaan syötetään alustavia tietoja. Tämä tapahtuu EFBlogPopulator
Luokka. Tämä luokka on rekisteröity palveluksi SetupBlog
laajennusmenetelmä.
public async Task Populate()
{
var posts = await _markdownBlogService.GetPages();
var languages = _markdownBlogService.LanguageList();
var languageEntities = await EnsureLanguages(languages);
await EnsureCategoriesAndPosts(posts, languageEntities);
await Context.SaveChangesAsync();
}
Sen voi nähdä seuraavasta kuvasta: Populate
Metodi, jota kutsumme mukaan _markdownBlogService.GetPages()
Tämä käy läpi makrdown-tiedostojamme ja kansoittaa joukon BlogViewModels
sisältää kaikki virat.
Sen jälkeen teemme samoin kielille. translated
Kansio kaikista EasyNMT:n avulla syntyneistä käännetyistä markown-tiedostoista (ks. täällä siitä, miten me sen osan teemme).
Sitten kutsumme meidän EnsureLanguages
menetelmä, jolla varmistetaan, että kaikki kielet ovat tietokannassa. Tämä on yksinkertainen menetelmä, joka tarkistaa, onko kieltä olemassa ja jos ei lisää sitä tietokantaan.
private async Task<List<LanguageEntity>> EnsureLanguages(Dictionary<string, List<string>> languages)
{
var languageList = languages.SelectMany(x => x.Value).ToList();
var currentLanguages = await Context.Languages.Select(x => x.Name).ToListAsync();
var languageEntities = new List<LanguageEntity>();
var enLang = new LanguageEntity { Name =MarkdownBaseService.EnglishLanguage };
if (!currentLanguages.Contains(MarkdownBaseService.EnglishLanguage)) Context.Languages.Add(enLang);
languageEntities.Add(enLang);
foreach (var language in languageList)
{
if (languageEntities.Any(x => x.Name == language)) continue;
var langItem = new LanguageEntity { Name = language };
if (!currentLanguages.Contains(language)) Context.Languages.Add(langItem);
languageEntities.Add(langItem);
}
await Context.SaveChangesAsync(); // Save the languages first so we can reference them in the blog posts
return languageEntities;
}
Huomaat, että tämä on ppretty yksinkertainen ja vain varmistaa, että kaikki kielet, jotka saimme markdown posts ovat tietokannassa; ja kuten täsmensimme, että Ids ovat automaattisesti tuotettuja meidän täytyy SaveChanges
varmistaakseen, että tunnisteet syntyvät.
Sitten kutsumme meidän EnsureCategoriesAndPosts
menetelmä, jolla varmistetaan, että kaikki luokat ja virat ovat tietokannassa. Tämä on hieman monimutkaisempaa, koska meidän on varmistettava, että luokat ovat tietokannassa, ja sen jälkeen meidän on varmistettava, että virat ovat tietokannassa.
private async Task EnsureCategoriesAndPosts(
IEnumerable<BlogPostViewModel> posts,
List<LanguageEntity> languageEntities)
{
var languages = languageEntities.ToDictionary(x => x.Name, x => x);
var currentPosts = await PostsQuery().ToListAsync();
foreach (var post in posts)
{
var existingCategories = Context.Categories.Local.ToList();
var currentPost =
currentPosts.FirstOrDefault(x => x.Slug == post.Slug && x.LanguageEntity.Name == post.Language);
await AddCategoriesToContext(post.Categories, existingCategories);
existingCategories = Context.Categories.Local.ToList();
await AddBlogPostToContext(post, languages[post.Language], existingCategories, currentPost);
}
}
Täällä käytämme Context.Categories.Local seurata kategorioita lisätään Context (Ne tallennetaan tietokantaan aikana SaveAsync
puhelu).
Huomaat, että kutsumme PostsQuery
Method of our Base class, joka on yksinkertainen menetelmä, joka palauttaa kyseenalaistaa BlogPostEntity
Voimme siis tiedustella tietokannasta virkoja.
protected IQueryable<BlogPostEntity> PostsQuery()=>Context.BlogPosts.Include(x => x.Categories)
.Include(x => x.LanguageEntity);
Sitten kutsumme sisään AddCategoriesToContext
menetelmä, jolla varmistetaan, että kaikki luokat ovat tietokannassa. Tämä on yksinkertainen menetelmä, joka tarkistaa, onko luokka olemassa ja jos ei lisää sitä tietokantaan.
private async Task AddCategoriesToContext(
IEnumerable<string> categoryList,
List<CategoryEntity> existingCategories)
{
foreach (var category in categoryList)
{
if (existingCategories.Any(x => x.Name == category)) continue;
var cat = new CategoryEntity { Name = category };
await Context.Categories.AddAsync(cat);
}
}
Tämäkin tarkistaa, onko luokka olemassa ja jos ei lisää sitä tietokantaan.
Sitten kutsumme sisään AddBlogPostToContext
metodin, tämä sitten kutsuu osaksi EFBaseService
tallentaa viesti tietokantaan.
private async Task AddBlogPostToContext(
BlogPostViewModel post,
LanguageEntity postLanguageEntity,
List<CategoryEntity> categories,
BlogPostEntity? currentPost)
{
await SavePost(post, currentPost, categories, new List<LanguageEntity> { postLanguageEntity });
}
Me teemme tämän kutsumalla SavePost
menetelmä, joka on menetelmä, joka tallentaa viestin tietokantaan. Tämä menetelmä on hieman monimutkainen, koska sen täytyy tarkistaa, onko viesti muuttunut ja päivittää viesti tietokantaan.
public async Task<BlogPostEntity?> SavePost(BlogPostViewModel post, BlogPostEntity? currentPost =null ,
List<CategoryEntity>? categories = null,
List<LanguageEntity>? languages = null)
{
if (languages == null)
languages = await Context.Languages.ToListAsync();
var postLanguageEntity = languages.FirstOrDefault(x => x.Name == post.Language);
if (postLanguageEntity == null)
{
Logger.LogError("Language {Language} not found", post.Language);
return null;
}
categories ??= await Context.Categories.Where(x => post.Categories.Contains(x.Name)).ToListAsync();
currentPost ??= await PostsQuery().Where(x=>x.Slug == post.Slug).FirstOrDefaultAsync();
try
{
var hash = post.HtmlContent.ContentHash();
var currentCategoryNames = currentPost?.Categories.Select(x => x.Name).ToArray() ?? Array.Empty<string>();
var categoriesChanged = false;
if (!currentCategoryNames.All(post.Categories.Contains) ||
!post.Categories.All(currentCategoryNames.Contains))
{
categoriesChanged = true;
Logger.LogInformation("Categories have changed for post {Post}", post.Slug);
}
var dateChanged = currentPost?.PublishedDate.UtcDateTime.Date != post.PublishedDate.ToUniversalTime().Date;
var titleChanged = currentPost?.Title != post.Title;
if (!titleChanged && !dateChanged && hash == currentPost?.ContentHash && !categoriesChanged)
{
Logger.LogInformation("Post {Post} has not changed", post.Slug);
return currentPost;
}
var blogPost = currentPost ?? new BlogPostEntity();
blogPost.Title = post.Title;
blogPost.Slug = post.Slug;
blogPost.OriginalMarkdown = post.OriginalMarkdown;
blogPost.HtmlContent = post.HtmlContent;
blogPost.PlainTextContent = post.PlainTextContent;
blogPost.ContentHash = hash;
blogPost.PublishedDate = post.PublishedDate;
blogPost.LanguageEntity = postLanguageEntity;
blogPost.Categories = categories.Where(x => post.Categories.Contains(x.Name)).ToList();
if (currentPost != null)
{
Logger.LogInformation("Updating post {Post}", post.Slug);
Context.BlogPosts.Update(blogPost); // Update the existing post
}
else
{
Logger.LogInformation("Adding new post {Post}", post.Slug);
Context.BlogPosts.Add(blogPost); // Add a new post
}
return blogPost;
}
catch (Exception e)
{
Logger.LogError(e, "Error adding post {Post}", post.Slug);
}
return null;
}
Kuten näette, tässä on paljon muutoshavaitsemista sen varmistamiseksi, että emme lisää viestejä, jotka eivät ole muuttuneet. Tarkistamme sisällön hasista, kategorioista, päivämäärästä ja otsikosta. Jos jokin näistä on muuttunut, päivitämme viestin tietokantaan.
Yksi asia on huomata, kuinka ärsyttävää DateTimeOffset on; meidän täytyy muuntaa se UTC:ksi ja sitten saada päivämäärä, jolloin sitä voi verrata. Tämä johtuu siitä, että DateTimeOffset
Siinä on aikakomponentti, ja haluamme vertailla vain ajankohtaa.
var dateChanged = currentPost?.PublishedDate.UtcDateTime.Date != post.PublishedDate.ToUniversalTime().Date;
Nyt meillä on täysin toimiva blogijärjestelmä, joka voidaan pakata markown-tiedostoista ja kääntää markown-tiedostoja. Seuraavassa osassa käsitellään yksinkertaista palvelua, jolla näytämme tietokantaan tallennettuja viestejä.