Att lägga till enhetens ram för bloggposter (Teil 5)
Se delar 1 och 2 och 3 och 4 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, i den mest uppenbara foldern
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
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
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 ) Vi använde EFBlogPopulator klass att göra detta.
Vår ström ser ut så här:
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:
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 vi kan få meddelanden i kategorier, i språk, i datumM SK2 och skicka meddelanden via paged
GetPostList
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
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.
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
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.
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.