# Att lägga till enhetens ram för bloggposter (Teil 5)

<!--category-- ASP.NET, Entity Framework -->
<datetime class="hidden">2024-08-18T01:20</datetime>

Se delar [1](/blog/addingentityframeworkforblogpostspt1) och [2](/blog/addingentityframeworkforblogpostspt2) och [3](/blog/addingentityframeworkforblogpostspt3) och [4](/blog/addingentityframeworkforblogpostspt4) för de tidigare stegen

# Inleiding

I tidigare delar har vi omfattat hur man sätter upp databasen, ,, hur våra kontroller och synsätt är strukturerade,,, hur vår tjänst fungerar, ,, och hur man planterar databasen med några inledande data.., i den här delen kommer vi att omfatta detaljer om hur EF-baserade tjänster fungerar och hur vi kan använda dem i våra kontrollörer.

Som vanligt kan ni se alla källor till detta på min GitHub [här](https://github.com/scottgal/mostlylucidweb/tree/main/Mostlylucid/Blog), i den mest uppenbara foldern

[TOC]

# bloggar

## File Based Services

Förr använde vi `MarkdownBlogService` för att få våra bloggposter och språk. Den här tjänsten injicerades i våra kontroller och synpunkter . Den denna tjänsten var en enkel tjänst som läste markerdown-filer från disket och återlämnade dem som `BlogViewModels`.

Det använde en statisk ordbok för att hålla bloggposterna och sedan återvände resultaten från ordboken

```csharp
  public async Task<PostListViewModel> GetPagedPosts(int page = 1, int pageSize = 10, string language = EnglishLanguage)
    {
        var model = new PostListViewModel();
        var posts = GetPageCache().Where(x => x.Value.Language == language)
            .Select(x => GetListModel(x.Value)).ToList();
        model.Posts = posts.OrderByDescending(x => x.PublishedDate).Skip((page - 1) * pageSize).Take(pageSize).ToList();
        model.TotalItems = posts.Count();
        model.PageSize = pageSize;
        model.Page = page;
        return await Task.FromResult(model);
    }
```

Det här är `GetPagedPosts` metoden från `MarkdownBlogService`. Den här metoden får bloggarna från cachet och ger dem tillbaka som `PostListViewModel`.

Att använda filer för att lagra markerdown-filer är fortfarande en bra metod, det gör att det är enkelt att lägga till meddelanden | ( | Jag sparar bara markerdown -filer på disket och kontrollerar dem i ) | Och det är ♪ ' ♪ enkelt att sköta ♪. ♪ Men vi vill använda databasen för att bevara meddelandena och språken

```mermaid
flowchart LR
    A[Write New Markdown File] -->|Checkin To Github| B(Github Action Triggers) -->  C(Builds Docker Image) --> D(Watchtower Pulls new Image) --> E(Site Updated)
   
  
```

## EF-baserade tjänster

I [föregående del]((/blog/addentityframeworkforblogpostspt 4) Jag visade hur vi fröde databasen med bloggdataM SK3 Den här uppdaterar varje gång vi omprövar och återstartar dockercontainern |[med hjälp av observationtorn ](blog/dockercompose)) Vi använde `EFBlogPopulator` klass att göra detta.

Vår ström ser ut så här:

```mermaid
   flowchart TD
    A[Write New Markdown File] -->|Checkin To Github| B(Github Action Triggers)
    B --> C(Builds Docker Image)
    C --> D(Watchtower Pulls new Image)
    D --> E{New Files Added?}
    E -->|Yes| F(Add File to Database)
    E -->|No| G(Skip Database Seeding)
    F --> H(Site Updated)
    G --> H(Site Updated)

```

Nu när vi har bloggarna i vår databas använder vi `EFBlogService` för att förse ut `IBlogService` gränssnitt:

```csharp
public interface IBlogService
{
   Task<List<string>> GetCategories();
    Task<List<BlogPostViewModel>> GetPosts(DateTime? startDate = null, string category = "");
    Task<PostListViewModel> GetPostsByCategory(string category, int page = 1, int pageSize = 10, string language = MarkdownBaseService.EnglishLanguage);
    Task<BlogPostViewModel?> GetPost(string slug, string language = "");
    Task<PostListViewModel> GetPagedPosts(int page = 1, int pageSize = 10, string language = MarkdownBaseService.EnglishLanguage);
    
    Task<List<PostListModel>> GetPostsForLanguage(DateTime? startDate = null, string category = "", string language = MarkdownBaseService.EnglishLanguage);
}
```

Det här är `IBlogService` gränssnitt. Detta är gränssnittet som våra kontroller använder för att få in bloggarna `EFBlogService` implementerar den här gränssnittet och använder `BlogContext` att få data från databasen.
Som med Out FileBased service [ovanför](#file-based-services) vi kan få meddelanden i kategorier, i språk, i datumM SK2 och skicka meddelanden via paged

### `GetPostList`

```csharp
    private async Task<PostListViewModel> GetPostList(int count, List<BlogPostEntity> posts, int page, int pageSize)
    {
        var languages = await NoTrackingQuery().Select(x =>
                new { x.Slug, x.LanguageEntity.Name }
            ).ToListAsync();

        var postModels = new List<PostListModel>();

        foreach (var postResult in posts)
        {
            var langArr = languages.Where(x => x.Slug == postResult.Slug).Select(x => x.Name).ToArray();

            postModels.Add(postResult.ToListModel(langArr));
        }

        var postListViewModel = new PostListViewModel
        {
            Page = page,
            PageSize = pageSize,
            TotalItems = count,
            Posts = postModels
        };

        return postListViewModel;
    }
```

Här använder vi vårt gemensamma `PostsQuery` men vi lägger till `NoTrackingQuery` som är en enkel metod som ger tillbaka en frågabar `BlogPostEntity` men med `AsNoTrackingWithIdentityResolution` lagt till. Det betyder att varelserna inte är spårade av kontexten och bara läser dem . Det är användbart när vi bara läser data utan att uppdatera den

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

Ni kan se att vi också får språken för postituserna och sedan skapar en `PostListViewModel` som är en struktur som accepterar sändning av information (`Page`, `PageSize` och `TotalItems`) och återförs till kontrollören

### `GetPost`

Vår huvudsakliga metod är `GetPost` metod som får en enda plats genom `Slug` och `Language`. Det här är en enkel metod som använder `PostsQuery` för att få posten och sedan återför den som ett `BlogPostViewModel`.
Ni kan se att den också har ett optionellt `Language` en parameter som är standard `EnglishLanguage` som är en konstant i vår `MarkdownBaseService` klass.

```csharp
  public async Task<BlogPostViewModel?> GetPost(string slug, string language = "")
    {
        if (string.IsNullOrEmpty(language)) language =MarkdownBaseService.EnglishLanguage;
        var post = await NoTrackingQuery().FirstOrDefaultAsync(x => x.Slug == slug && x.LanguageEntity.Name == language);
        if (post == null) return null;
        var langArr = await GetLanguagesForSlug(slug);
        return post.ToPostModel(langArr);
    }
```

Det här använder också vår gemensamma metod `GetLanguagesForSlug` som får språket för en post. Det här är en enkel metod som återvänder språken för en

```csharp
    private async Task<List<string>> GetLanguagesForSlug(string slug)=> await NoTrackingQuery()
        .Where(x => x.Slug == slug).Select(x=>x.LanguageEntity.Name).ToListAsync();
```

### `GetPostsByCategory`

Den här metoden får posterna i kategorier ( som ASP.NET & Beståndsdelens ram för den här posten `PostsQuery` att få posterna och sen filtrerar de efter kategorin. Den återsätter sedan posterna som ett `PostListViewModel`.

```csharp
    public async Task<PostListViewModel> GetPostsByCategory(string category, int page = 1, int pageSize = 10,
        string language = MarkdownBaseService.EnglishLanguage)
    {
        
        var count = await NoTrackingQuery()
            .Where(x => x.Categories.Any(c => c.Name == category) && x.LanguageEntity.Name == language).CountAsync();
        var posts = await PostsQuery()
            .Where(x => x.Categories.Any(c => c.Name == category) && x.LanguageEntity.Name == language)
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync();

        var languages = await GetLanguagesForSlugs(posts.Select(x => x.Slug).ToList());
        var postListViewModel = new PostListViewModel
        {
            Page = page,
            PageSize = pageSize,
            TotalItems = count,
            Posts = posts.Select(x => x.ToListModel(
                languages.FirstOrDefault(entry => entry.Key == x.Slug).Value.ToArray())).ToList()
        };
        return postListViewModel;
    }
```

# I slutsats

Ni kan se att EF-baserade tjänster är lite mer komplexa än File Based-tjänsterna men de är mer flexibela och kan användas i mer komplicerade scenarior.
I framtiden kommer vi att bygga på dessa och lägga till tjänster som inlineredigering och kommentarer.
Vi ska också titta på hur vi kan synchronisera dessa över flera system.