Created
February 18, 2025 06:51
-
-
Save fnmssteam/2d611f58cb17eeb519b6d945619d0d7b to your computer and use it in GitHub Desktop.
DeepSeek EF Core API Exercise
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using Microsoft.EntityFrameworkCore.Migrations; | |
#nullable disable | |
namespace DeepSeekApiCore.Migrations | |
{ | |
/// <inheritdoc /> | |
public partial class InitialCreate : Migration | |
{ | |
/// <inheritdoc /> | |
protected override void Up(MigrationBuilder migrationBuilder) | |
{ | |
migrationBuilder.CreateTable( | |
name: "Categories", | |
columns: table => new | |
{ | |
Id = table.Column<int>(type: "int", nullable: false) | |
.Annotation("SqlServer:Identity", "1, 1"), | |
Name = table.Column<string>(type: "nvarchar(max)", nullable: false), | |
Description = table.Column<string>(type: "nvarchar(max)", nullable: false) | |
}, | |
constraints: table => | |
{ | |
table.PrimaryKey("PK_Categories", x => x.Id); | |
}); | |
migrationBuilder.CreateTable( | |
name: "Tags", | |
columns: table => new | |
{ | |
Id = table.Column<int>(type: "int", nullable: false) | |
.Annotation("SqlServer:Identity", "1, 1"), | |
Name = table.Column<string>(type: "nvarchar(max)", nullable: false) | |
}, | |
constraints: table => | |
{ | |
table.PrimaryKey("PK_Tags", x => x.Id); | |
}); | |
migrationBuilder.CreateTable( | |
name: "Posts", | |
columns: table => new | |
{ | |
Id = table.Column<int>(type: "int", nullable: false) | |
.Annotation("SqlServer:Identity", "1, 1"), | |
Title = table.Column<string>(type: "nvarchar(max)", nullable: false), | |
Content = table.Column<string>(type: "nvarchar(max)", nullable: false), | |
CreatedDate = table.Column<DateOnly>(type: "date", nullable: false), | |
CategoryId = table.Column<int>(type: "int", nullable: false), | |
AuthorName = table.Column<string>(type: "nvarchar(max)", nullable: false), | |
IsDeleted = table.Column<bool>(type: "bit", nullable: false) | |
}, | |
constraints: table => | |
{ | |
table.PrimaryKey("PK_Posts", x => x.Id); | |
table.ForeignKey( | |
name: "FK_Posts_Categories_CategoryId", | |
column: x => x.CategoryId, | |
principalTable: "Categories", | |
principalColumn: "Id", | |
onDelete: ReferentialAction.Cascade); | |
}); | |
migrationBuilder.CreateTable( | |
name: "Comments", | |
columns: table => new | |
{ | |
Id = table.Column<int>(type: "int", nullable: false) | |
.Annotation("SqlServer:Identity", "1, 1"), | |
Text = table.Column<string>(type: "nvarchar(max)", nullable: false), | |
CreatedDate = table.Column<DateOnly>(type: "date", nullable: false), | |
PostId = table.Column<int>(type: "int", nullable: false), | |
UserEmail = table.Column<string>(type: "nvarchar(max)", nullable: false) | |
}, | |
constraints: table => | |
{ | |
table.PrimaryKey("PK_Comments", x => x.Id); | |
table.ForeignKey( | |
name: "FK_Comments_Posts_PostId", | |
column: x => x.PostId, | |
principalTable: "Posts", | |
principalColumn: "Id", | |
onDelete: ReferentialAction.Cascade); | |
}); | |
migrationBuilder.CreateTable( | |
name: "PostTag", | |
columns: table => new | |
{ | |
PostsId = table.Column<int>(type: "int", nullable: false), | |
TagsId = table.Column<int>(type: "int", nullable: false) | |
}, | |
constraints: table => | |
{ | |
table.PrimaryKey("PK_PostTag", x => new { x.PostsId, x.TagsId }); | |
table.ForeignKey( | |
name: "FK_PostTag_Posts_PostsId", | |
column: x => x.PostsId, | |
principalTable: "Posts", | |
principalColumn: "Id", | |
onDelete: ReferentialAction.Cascade); | |
table.ForeignKey( | |
name: "FK_PostTag_Tags_TagsId", | |
column: x => x.TagsId, | |
principalTable: "Tags", | |
principalColumn: "Id", | |
onDelete: ReferentialAction.Cascade); | |
}); | |
migrationBuilder.CreateIndex( | |
name: "IX_Comments_PostId", | |
table: "Comments", | |
column: "PostId"); | |
migrationBuilder.CreateIndex( | |
name: "IX_Posts_CategoryId", | |
table: "Posts", | |
column: "CategoryId"); | |
migrationBuilder.CreateIndex( | |
name: "IX_PostTag_TagsId", | |
table: "PostTag", | |
column: "TagsId"); | |
} | |
/// <inheritdoc /> | |
protected override void Down(MigrationBuilder migrationBuilder) | |
{ | |
migrationBuilder.DropTable( | |
name: "Comments"); | |
migrationBuilder.DropTable( | |
name: "PostTag"); | |
migrationBuilder.DropTable( | |
name: "Posts"); | |
migrationBuilder.DropTable( | |
name: "Tags"); | |
migrationBuilder.DropTable( | |
name: "Categories"); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.EntityFrameworkCore.Migrations; | |
#nullable disable | |
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional | |
namespace DeepSeekApiCore.Migrations | |
{ | |
/// <inheritdoc /> | |
public partial class AddSeedData : Migration | |
{ | |
/// <inheritdoc /> | |
protected override void Up(MigrationBuilder migrationBuilder) | |
{ | |
migrationBuilder.InsertData( | |
table: "Categories", | |
columns: new[] { "Id", "Description", "Name" }, | |
values: new object[,] | |
{ | |
{ 1, "Health is good.", "Health" }, | |
{ 2, "Math is hard.", "Math" }, | |
{ 3, "AI is scary.", "AI" } | |
}); | |
migrationBuilder.InsertData( | |
table: "Tags", | |
columns: new[] { "Id", "Name" }, | |
values: new object[,] | |
{ | |
{ 1, "Linear Algebra" }, | |
{ 2, "Deep Learning" }, | |
{ 3, "Weightlifting" } | |
}); | |
} | |
/// <inheritdoc /> | |
protected override void Down(MigrationBuilder migrationBuilder) | |
{ | |
migrationBuilder.DeleteData( | |
table: "Categories", | |
keyColumn: "Id", | |
keyValue: 1); | |
migrationBuilder.DeleteData( | |
table: "Categories", | |
keyColumn: "Id", | |
keyValue: 2); | |
migrationBuilder.DeleteData( | |
table: "Categories", | |
keyColumn: "Id", | |
keyValue: 3); | |
migrationBuilder.DeleteData( | |
table: "Tags", | |
keyColumn: "Id", | |
keyValue: 1); | |
migrationBuilder.DeleteData( | |
table: "Tags", | |
keyColumn: "Id", | |
keyValue: 2); | |
migrationBuilder.DeleteData( | |
table: "Tags", | |
keyColumn: "Id", | |
keyValue: 3); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace DeepSeekApiCore.Entities; | |
public class Category | |
{ | |
public int Id { get; set; } | |
public string Name { get; set; } | |
public string Description { get; set; } | |
public List<Post> Posts { get; set; } = new(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace DeepSeekApiCore.Entities; | |
public class Comment | |
{ | |
public int Id { get; set; } | |
public string Text { get; set; } | |
public DateOnly CreatedDate { get; set; } | |
public int PostId { get; set; } | |
public string UserEmail { get; set; } | |
public Post Post { get; set; } = new(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace DeepSeekApiCore.DTOs.Comment; | |
public class CommentDto | |
{ | |
public string PostTitle { get; set; } | |
public string Text { get; set; } | |
public string UserEmail { get; set; } | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.ComponentModel.DataAnnotations; | |
namespace DeepSeekApiCore.DTOs.Comment; | |
public class CreateCommentDto | |
{ | |
[Required] | |
[MaxLength(500)] | |
public string Text { get; set; } | |
[EmailAddress] | |
public string UserEmail { get; set; } | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.ComponentModel.DataAnnotations; | |
namespace DeepSeekApiCore.DTOs.Post; | |
public class CreatePostDto | |
{ | |
[Required] | |
[MaxLength(100)] | |
public string Title { get; set; } | |
public string Content { get; set; } | |
public int CategoryId { get; set; } | |
public string AuthorName { get; set; } | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using DeepSeekApiCore.Entities; | |
using Microsoft.EntityFrameworkCore; | |
namespace DeepSeekApiCore.Persistence; | |
public class DeepSeekApiCoreDbContext(DbContextOptions<DeepSeekApiCoreDbContext> context) : DbContext(context) | |
{ | |
public DbSet<Category> Categories { get; set; } | |
public DbSet<Comment> Comments { get; set; } | |
public DbSet<Post> Posts { get; set; } | |
public DbSet<Tag> Tags { get; set; } | |
protected override void OnConfiguring(DbContextOptionsBuilder options) | |
{ | |
options.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=DeepSeekApiCore;Trusted_Connection=True;"); | |
} | |
protected override void OnModelCreating(ModelBuilder builder) | |
{ | |
builder.Entity<Post>() | |
.HasOne(p => p.Category) | |
.WithMany(c => c.Posts) | |
.HasForeignKey(p => p.CategoryId); | |
builder.Entity<Post>() | |
.HasMany(p => p.Comments) | |
.WithOne(c => c.Post) | |
.HasForeignKey(c => c.PostId); | |
builder.Entity<Post>() | |
.HasMany(p => p.Tags) | |
.WithMany(t => t.Posts); | |
builder.Entity<Category>() | |
.HasData( | |
new Category() { Id = 1, Name = "Health", Description = "Health is good." }, | |
new Category() { Id = 2, Name = "Math", Description = "Math is hard." }, | |
new Category() { Id = 3, Name = "AI", Description = "AI is scary." } | |
); | |
builder.Entity<Tag>() | |
.HasData( | |
new Tag() { Id = 1, Name = "Linear Algebra" }, | |
new Tag() { Id = 2, Name = "Deep Learning" }, | |
new Tag() { Id = 3, Name = "Weightlifting" } | |
); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace DeepSeekApiCore.Entities; | |
public class Post | |
{ | |
public int Id { get; set; } | |
public string Title { get; set; } | |
public string Content { get; set; } | |
public DateOnly CreatedDate { get; set; } = DateOnly.FromDateTime(DateTime.Now); | |
public int CategoryId { get; set; } | |
public string AuthorName { get; set; } | |
public bool IsDeleted { get; set; } = false; | |
public Category Category { get; set; } = new(); | |
public List<Comment> Comments { get; set; } = new(); | |
public List<Tag> Tags { get; set; } = new(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using DeepSeekApiCore.DTOs.Comment; | |
using DeepSeekApiCore.DTOs.Post; | |
using DeepSeekApiCore.Entities; | |
using DeepSeekApiCore.Persistence; | |
using Microsoft.AspNetCore.Mvc; | |
using Microsoft.EntityFrameworkCore; | |
using Microsoft.IdentityModel.Tokens; | |
namespace DeepSeekApiCore.Controllers; | |
[ApiController] | |
[Route("[controller]")] | |
public class PostController : ControllerBase | |
{ | |
private readonly DeepSeekApiCoreDbContext _context; | |
public PostController(DeepSeekApiCoreDbContext context) | |
{ | |
_context = context; | |
} | |
[HttpGet] | |
public async Task<ActionResult<IEnumerable<PostDto>>> Index([FromQuery] string? search, [FromQuery] string? filter) | |
{ | |
var query = _context.Posts | |
.Include(p => p.Comments) | |
.Include(p => p.Tags) | |
.Include(p => p.Category) | |
.Where(p => !p.IsDeleted); | |
if (!search.IsNullOrEmpty()) | |
{ | |
search = search.ToLower(); | |
query = query.Where(p => p.Title.ToLower().Contains(search) || p.Content.ToLower().Contains(search)); | |
} | |
if (!filter.IsNullOrEmpty()) | |
{ | |
filter = filter.ToLower(); | |
query = query.Where(p => p.Category.Name.ToLower() == filter || p.Tags.Any(t => t.Name.ToLower() == filter)); | |
} | |
var posts = await query.ToListAsync(); | |
List<PostDto> mappedPosts = new List<PostDto>(); | |
foreach (var post in posts) | |
{ | |
mappedPosts.Add(new PostDto() | |
{ | |
Id = post.Id, | |
Title = post.Title, | |
CommentCount = post.Comments.Count, | |
RecentCommentDate = post.Comments.OrderByDescending(c => c.CreatedDate).FirstOrDefault()?.CreatedDate, | |
Tags = post.Tags.Select(t => t.Name).ToList() | |
}); | |
} | |
return Ok(mappedPosts); | |
} | |
[HttpGet("/{id}")] | |
public async Task<ActionResult<PostDto>> Get(int id) | |
{ | |
var post = await _context.Posts | |
.Include(p => p.Comments) | |
.Where(p => !p.IsDeleted && p.Id == id) | |
.FirstOrDefaultAsync(); | |
if (post == null) | |
{ | |
return NotFound(); | |
} | |
var postDto = new PostDto() | |
{ | |
Id = post.Id, | |
Title = post.Title, | |
CommentCount = post.Comments.Count, | |
RecentCommentDate = post.Comments.OrderByDescending(c => c.CreatedDate).FirstOrDefault()?.CreatedDate, | |
Tags = post.Tags.Select(t => t.Name).ToList() | |
}; | |
return Ok(postDto); | |
} | |
[HttpPost] | |
public async Task<ActionResult> Create(CreatePostDto dto) | |
{ | |
Post post = new Post() | |
{ | |
Title = dto.Title, | |
Content = dto.Content, | |
CreatedDate = DateOnly.FromDateTime(DateTime.UtcNow), | |
AuthorName = dto.AuthorName, | |
CategoryId = dto.CategoryId, | |
}; | |
_context.Posts.Add(post); | |
await _context.SaveChangesAsync(); | |
return Ok(); | |
} | |
[HttpDelete("/{id}")] | |
public async Task<ActionResult> Delete(int id) | |
{ | |
var post = await _context.Posts | |
.Where(p => p.Id == id && !p.IsDeleted) | |
.FirstOrDefaultAsync(); | |
if (post == null) | |
{ | |
return NotFound(); | |
} | |
post.IsDeleted = true; | |
await _context.SaveChangesAsync(); | |
return Ok(); | |
} | |
[HttpPatch("/{id}/restore")] | |
public async Task<ActionResult> Restore(int id) | |
{ | |
var post = await _context.Posts | |
.Where(p => p.Id == id && p.IsDeleted) | |
.FirstOrDefaultAsync(); | |
if (post == null) | |
{ | |
return NotFound(); | |
} | |
post.IsDeleted = false; | |
await _context.SaveChangesAsync(); | |
return Ok(); | |
} | |
[HttpPost("/{id}/comments")] | |
public async Task<ActionResult<CommentDto>> CreatePostComment(int id, CreateCommentDto dto) | |
{ | |
var post = await _context.Posts | |
.Where(p => p.Id == id && !p.IsDeleted) | |
.Include(p => p.Comments) | |
.FirstOrDefaultAsync(); | |
if (post == null) | |
{ | |
return NotFound(); | |
} | |
Comment comment = new Comment() | |
{ | |
Text = dto.Text, | |
UserEmail = dto.UserEmail, | |
CreatedDate = DateOnly.FromDateTime(DateTime.UtcNow), | |
}; | |
post.Comments.Add(comment); | |
await _context.SaveChangesAsync(); | |
return Ok(new CommentDto() | |
{ | |
PostTitle = post.Title, | |
Text = comment.Text, | |
UserEmail = comment.UserEmail, | |
}); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace DeepSeekApiCore.DTOs.Post; | |
public class PostDto | |
{ | |
public int Id { get; set; } | |
public string Title { get; set; } | |
public int CommentCount { get; set; } | |
public DateOnly? RecentCommentDate { get; set; } | |
public List<string> Tags { get; set; } | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using DeepSeekApiCore.Persistence; | |
var builder = WebApplication.CreateBuilder(args); | |
// Add services to the container. | |
builder.Services.AddControllers(); | |
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle | |
builder.Services.AddEndpointsApiExplorer(); | |
builder.Services.AddSwaggerGen(); | |
builder.Services.AddDbContext<DeepSeekApiCoreDbContext>(); | |
var app = builder.Build(); | |
// Configure the HTTP request pipeline. | |
if (app.Environment.IsDevelopment()) | |
{ | |
app.UseSwagger(); | |
app.UseSwaggerUI(); | |
} | |
app.UseHttpsRedirection(); | |
app.UseAuthorization(); | |
app.MapControllers(); | |
app.Run(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace DeepSeekApiCore.Entities; | |
public class Tag | |
{ | |
public int Id { get; set; } | |
public string Name { get; set; } | |
public List<Post> Posts { get; set; } = new(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment