# Het 'Entity Framework' toevoegen voor Blog Posts (Pt. 4)

<!--category-- ASP.NET, Entity Framework -->
<datetime class="hidden">2024-08-17T20:00</datetime>

Zie delen [1](/blog/addingentityframeworkforblogpostspt1) en [2](/blog/addingentityframeworkforblogpostspt2) en [3](/blog/addingentityframeworkforblogpostspt3) voor de vorige stappen.

# Inleiding

In eerdere delen hebben we behandeld hoe de database op te zetten, hoe onze controllers en visies zijn gestructureerd, en hoe onze diensten werktenM SK2 In deze deel zullen we de details over hoe je de database met een aantal begingegevens inzet en hoe de EF-gebaseerde diensten werken .

Zoals gewoonlijk zie je hier alle bronnen voor op mijn GitHub. [Hier.](https://github.com/scottgal/mostlylucidweb/tree/main/Mostlylucid/Blog), in de meest duidelijke folder/BloggidsM SK2

[TOC]

# Zedding van de database

In het vorige deel hebben we behandeld hoe we [Initialiseer en opstelling van de dienste.](/blog/addingentityframeworkforblogpostspt2#setup). In dit deel zullen we ' behandelen hoe je de database inzet met een aantal begingegevens. `EFBlogPopulator` class. Deze klas is geregistreerd als een dienst in de `SetupBlog` Verlengingsmethode.

```csharp
    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();
    }
```

Je ziet dat in de `Populate` De methode die we in de `_markdownBlogService.GetPages()` Dit loopt door onze makrdown-bestanden en bevolkt een hoop van `BlogViewModels` containing all the posts.
Dan doen we hetzelfde voor de talen; dit kijkt naar onze `translated` gids voor alle vertaalde markerdown-bestanden die we genereerden met EasyNMT (sien [Hier.](/blog/autotranslatingmarkdownfiles) voor hoe we dat deel doen.

## Voeg de talen toe

Dan roepen we in onze `EnsureLanguages` methode die ervoor zorgt dat alle talen in de database zijn.. Dit is een eenvoudige methode om te controleren of de taal bestaat en of ze niet aan de database wordt toegevoegd.

```csharp
  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;
    }
```

Je zal zien dat dit ppretty simpel is en ervoor zorgt dat alle talen die we van de markdown-posts kregen in de database zitten. `SaveChanges` om te zorgen dat de Ids worden gegenereerd.

### Categories en posten toevoegen

Dan roepen we in onze `EnsureCategoriesAndPosts` methode die ervoor zorgt dat alle categorieën en posities in de database zijn.

```csharp
    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);
        }
    }
```

Hier gebruiken we de Context.Categorieën.Local om de categorieën te volgen die momenteel bijgevoegd zijn in het Context (zeiM SK3in de Databasis gestopt zijn tijdens de `SaveAsync` Call).
Je kunt zien dat we in de `PostsQuery` Het is een eenvoudige methode die een vraagbaar antwoord terugbrengt op de basisklas. `BlogPostEntity` Dus kunnen we de database vragen voor de posts.

```csharp
  protected IQueryable<BlogPostEntity> PostsQuery()=>Context.BlogPosts.Include(x => x.Categories)
        .Include(x => x.LanguageEntity);
   
```

#### De categorieën toevoegen.

Dan roepen we in de `AddCategoriesToContext` methode die ervoor zorgt dat alle categorieën in de database zitten. Dit is een eenvoudige methode om te controleren of de categorie bestaat en of ze niet aan de database wordt toegevoegd.

```csharp
    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);
        }
    }

```

Nogmaals, dit controleert of de categorie bestaat en als niet voegt ze toe in de database.

#### Het toevoegen van de blogposts

Dan roepen we in de `AddBlogPostToContext` methode, dit roept dan in de `EFBaseService` om de post in de database te slaan.

```csharp
    private async Task AddBlogPostToContext(
        BlogPostViewModel post,
        LanguageEntity postLanguageEntity,
        List<CategoryEntity> categories,
        BlogPostEntity? currentPost)
    {
        await SavePost(post, currentPost, categories, new List<LanguageEntity> { postLanguageEntity });
    }
```

We doen dit door de `SavePost` methode die de post in de database bewaart. Deze methode is een beetje complex omdat ze moet controleren of de post veranderd is en als dat zo is, de post opdateert in de databasis.

```csharp

   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;
    }

```

Zoals je ziet heeft dit een LITTLE veranderingen waarnemen om ervoor te zorgen dat we geen posts die niet veranderd zijn hervoegen.

Eén ding dat je moet opmerken is hoe vervelend het is om een DateTimeOffset te controleren:; we moeten het omzetten naar UTC en dan de datum krijgen om het te vergelijken. `DateTimeOffset` Het heeft een tijdscomponent en we willen alleen de datum vergelijken.

```csharp
var dateChanged = currentPost?.PublishedDate.UtcDateTime.Date != post.PublishedDate.ToUniversalTime().Date;
```

# In slotting:

Nu hebben we een volledig werkend blogsysteem dat kan worden bevolkt van markdown-bestanden en vertaalde markdownbestanden.