我无法从数据库中获取.NET 7.0 Web API上的推文回复。

huangapple go评论99阅读模式
英文:

I can't get Tweet Replies from database on my .NET 7.0 Web API

问题

我正在制作一个Twitter克隆API。当我尝试通过ID获取带有回复的推文时,即使有回复,它也返回null。

Tweet.cs

  1. using TwitterCloneApp.Core.Interfaces;
  2. namespace TwitterCloneApp.Core.Models
  3. {
  4. public class Tweet : IBaseEntity, IDeletable, IUpdatedAt, ICreatedAt
  5. {
  6. public int Id { get; set; }
  7. public int UserId { get; set; }
  8. public string Content { get; set; }
  9. public User User { get; set; }
  10. public bool isMainTweet { get; set; }
  11. public bool IsDeleted { get; set; } = false;
  12. public DateTime? DeletedAt { get; set; }
  13. public DateTime? UpdatedAt { get; set; }
  14. public DateTime? CreatedAt { get; set; }
  15. public ICollection<Tag>? Tags { get; set; } // Many-to-Many ilişkisi için koleksiyon
  16. public ICollection<Tweet>? Replies { get; set; }
  17. public ICollection<Like>? Likes { get; set; }
  18. }
  19. }

TwReply.Cs(用于关系)

  1. namespace TwitterCloneApp.Core.Models
  2. {
  3. public class TwReply
  4. {
  5. public int TweetId { get; set; }
  6. public int ReplyId { get; set; }
  7. public Tweet Tweet { get; set; }
  8. public Tweet Reply { get; set; }
  9. }
  10. }

TweetDto.cs

  1. using TwitterCloneApp.DTO.Tag;
  2. using TwitterCloneApp.DTO.User;
  3. namespace TwitterCloneApp.DTO.Tweet
  4. {
  5. public class TweetDto
  6. {
  7. public int Id { get; set; }
  8. public UserResponseDto User { get; set; }
  9. public string? Content { get; set; }
  10. public DateTime? CreatedAt { get; set; }
  11. public int LikeCount { get; set; }
  12. public List<TagResponseDto>? Tags { get; set; }
  13. public List<ReplyResponseDto>? Replies { get; set; }
  14. }
  15. }

ReplyResponseDto.cs

  1. using TwitterCloneApp.DTO.User;
  2. namespace TwitterCloneApp.DTO.Tweet
  3. {
  4. public class ReplyResponseDto
  5. {
  6. public UserResponseDto User { get; set; }
  7. public string Content { get; set; }
  8. public DateTime? CreatedAt { get; set; }
  9. public int LikeCount { get; set; }
  10. }
  11. }

UserResponseDto.cs

  1. namespace TwitterCloneApp.DTO.User
  2. {
  3. public class UserResponseDto
  4. {
  5. public string UserName { get; set; }
  6. public string DisplayName { get; set; }
  7. public string? ProfileImg { get; set; }
  8. }
  9. }

TweetController部分

  1. [HttpGet("[action]")]
  2. public async Task<IActionResult> GetTweetByIdAsync(int id)
  3. {
  4. var tweet = await _tweetService.GetTweetByIdAsync(id);
  5. return Ok(tweet);
  6. }

TweetService部分

  1. public async Task<TweetDto> GetTweetByIdAsync(int tweetId)
  2. {
  3. return await _tweetRepository.GetTweetWithTagsByIdAsync(tweetId);
  4. }

TweetRepository部分

  1. public async Task<TweetDto> GetTweetWithTagsByIdAsync(int tweetId)
  2. {
  3. var tweet = await _tweet.Include(t => t.Tags)
  4. .Include(t => t.Replies).ThenInclude(reply => reply.User)
  5. .Include(t => t.User)
  6. .Include(t => t.Likes)
  7. .FirstOrDefaultAsync(t => t.Id == tweetId);
  8. if (tweet == null)
  9. {
  10. return null; // 或者执行必要的操作
  11. }
  12. var tweetDto = new TweetDto
  13. {
  14. Id = tweet.Id,
  15. Content = tweet.Content,
  16. CreatedAt = tweet.CreatedAt,
  17. LikeCount = tweet.Likes?.Count ?? 0,
  18. Tags = tweet.Tags?.Select(t => new TagResponseDto
  19. {
  20. Name = t.Name
  21. }).ToList(),
  22. User = new UserResponseDto
  23. {
  24. UserName = tweet.User.UserName,
  25. DisplayName = tweet.User.DisplayName,
  26. ProfileImg = tweet.User.ProfileImg
  27. },
  28. Replies = tweet.Replies?.Select(reply => new ReplyResponseDto
  29. {
  30. User = new UserResponseDto
  31. {
  32. UserName = reply.User.UserName,
  33. DisplayName = reply.User.DisplayName,
  34. ProfileImg = reply.User.ProfileImg
  35. },
  36. Content = reply.Content,
  37. CreatedAt = reply.CreatedAt,
  38. LikeCount = reply.Likes?.Count ?? 0
  39. }).ToList()
  40. };
  41. return tweetDto;
  42. }

AppDbContext.cs

  1. using Microsoft.EntityFrameworkCore;
  2. using System.Reflection;
  3. using TwitterCloneApp.Core.Models;
  4. namespace TwitterCloneApp.Repository
  5. {
  6. public class AppDbContext : DbContext
  7. {
  8. public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
  9. {
  10. }
  11. public DbSet<User> Users { get; set; }
  12. public DbSet<Tweet> Tweets { get; set; }
  13. public DbSet<Tag> Tags { get; set; }
  14. public DbSet<Like> Likes { get; set; }
  15. public DbSet<TwReply> TwReplies { get; set; }
  16. protected override void OnModelCreating(ModelBuilder modelBuilder)
  17. {
  18. modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
  19. var relationships = modelBuilder.Model.GetEntityTypes()
  20. .SelectMany(e => e.GetForeignKeys());
  21. foreach (var relationship in relationships)
  22. {
  23. relationship.DeleteBehavior = DeleteBehavior.Restrict;
  24. }
  25. base.OnModelCreating(modelBuilder);
  26. }
  27. }
  28. }

推文ID为1有2个回复(3和10),但输出为:

  1. {
  2. "id": 1,
  3. "user": {
  4. "userName": "asdasdasd",
  5. "displayName": "asdasdasd",
  6. "profileImg": "string"
  7. },
  8. "content": "First tweet",
  9. "createdAt": null,
  10. "likeCount": 3,
  11. "tags": [
  12. {
  13. "name": "#testingSeed1"
  14. },
  15. {
  16. "name": "#testingSeed2"
  17. },
  18. {
  19. "name": "#testing"
  20. }
  21. ],
  22. "replies": []
  23. }

我尝试在获取推文时获取回复,但程序不会获取回复。我使用的是Entity Framework Core。

英文:

I am making a Twitter Clone API. When I try to get a Tweet by Id with its replies, it returns null even if there is a reply.
Tweet.cs

  1. using TwitterCloneApp.Core.Interfaces;
  2. namespace TwitterCloneApp.Core.Models
  3. {
  4. public class Tweet : IBaseEntity, IDeletable, IUpdatedAt, ICreatedAt
  5. {
  6. public int Id { get; set; }
  7. public int UserId { get; set; }
  8. public string Content { get; set; }
  9. public User User { get; set; }
  10. public bool isMainTweet { get; set; }
  11. public bool IsDeleted { get; set; } = false;
  12. public DateTime? DeletedAt { get; set; }
  13. public DateTime? UpdatedAt { get; set; }
  14. public DateTime? CreatedAt { get; set; }
  15. public ICollection&lt;Tag&gt;? Tags { get; set; } // Many-to-Many ilişkisi i&#231;in koleksiyon
  16. public ICollection&lt;Tweet&gt;? Replies { get; set; }
  17. public ICollection&lt;Like&gt;? Likes { get; set; }
  18. }
  19. }

TwReply.Cs (for relation)

  1. namespace TwitterCloneApp.Core.Models
  2. {
  3. public class TwReply
  4. {
  5. public int TweetId { get; set; }
  6. public int ReplyId { get; set; }
  7. public Tweet Tweet { get; set; }
  8. public Tweet Reply { get; set; }
  9. }
  10. }

TweetDto.cs

  1. using TwitterCloneApp.DTO.Tag;
  2. using TwitterCloneApp.DTO.User;
  3. namespace TwitterCloneApp.DTO.Tweet
  4. {
  5. public class TweetDto
  6. {
  7. public int Id { get; set; }
  8. public UserResponseDto User { get; set; }
  9. public string? Content { get; set; }
  10. public DateTime? CreatedAt { get; set; }
  11. public int LikeCount { get; set; }
  12. public List&lt;TagResponseDto&gt;? Tags { get; set; }
  13. public List&lt;ReplyResponseDto&gt;? Replies { get; set; }
  14. }
  15. }

ReplyResponseDto.cs

  1. using TwitterCloneApp.DTO.User;
  2. namespace TwitterCloneApp.DTO.Tweet
  3. {
  4. public class ReplyResponseDto
  5. {
  6. public UserResponseDto User { get; set; }
  7. public string Content { get; set; }
  8. public DateTime? CreatedAt { get; set; }
  9. public int LikeCount { get; set; }
  10. }
  11. }

UserResponseDto.cs

  1. namespace TwitterCloneApp.DTO.User
  2. {
  3. public class UserResponseDto
  4. {
  5. public string UserName { get; set; }
  6. public string DisplayName { get; set; }
  7. public string? ProfileImg { get; set; }
  8. }
  9. }

TweetController part

  1. [HttpGet(&quot;[action]&quot;)]
  2. public async Task&lt;IActionResult&gt; GetTweetByIdAsync(int id)
  3. {
  4. var tweet = await _tweetService.GetTweetByIdAsync(id);
  5. return Ok(tweet);
  6. }

TweetService part

  1. public async Task&lt;TweetDto&gt; GetTweetByIdAsync(int tweetId)
  2. {
  3. return await _tweetRepository.GetTweetWithTagsByIdAsync(tweetId);
  4. }

TweetRepository part

  1. public async Task&lt;TweetDto&gt; GetTweetWithTagsByIdAsync(int tweetId)
  2. {
  3. var tweet = await _tweet.Include(t =&gt; t.Tags)
  4. .Include(t =&gt; t.Replies).ThenInclude(reply =&gt; reply.User)
  5. .Include(t =&gt; t.User)
  6. .Include(t =&gt; t.Likes)
  7. .FirstOrDefaultAsync(t =&gt; t.Id == tweetId);
  8. if (tweet == null)
  9. {
  10. return null; // veya gerekli işlemleri yapın
  11. }
  12. var tweetDto = new TweetDto
  13. {
  14. Id = tweet.Id,
  15. Content = tweet.Content,
  16. CreatedAt = tweet.CreatedAt,
  17. LikeCount = tweet.Likes?.Count ?? 0,
  18. Tags = tweet.Tags?.Select(t =&gt; new TagResponseDto
  19. {
  20. Name = t.Name
  21. }).ToList(),
  22. User = new UserResponseDto
  23. {
  24. UserName = tweet.User.UserName,
  25. DisplayName = tweet.User.DisplayName,
  26. ProfileImg = tweet.User.ProfileImg
  27. },
  28. Replies = tweet.Replies?.Select(reply =&gt; new ReplyResponseDto
  29. {
  30. User = new UserResponseDto
  31. {
  32. UserName = reply.User.UserName,
  33. DisplayName = reply.User.DisplayName,
  34. ProfileImg = reply.User.ProfileImg
  35. },
  36. Content = reply.Content,
  37. CreatedAt = reply.CreatedAt,
  38. LikeCount = reply.Likes?.Count ?? 0
  39. }).ToList()
  40. };
  41. return tweetDto;
  42. }

AppDbContext.cs

  1. using Microsoft.EntityFrameworkCore;
  2. using System.Reflection;
  3. using TwitterCloneApp.Core.Models;
  4. namespace TwitterCloneApp.Repository
  5. {
  6. public class AppDbContext : DbContext
  7. {
  8. public AppDbContext(DbContextOptions&lt;AppDbContext&gt; options) : base(options)
  9. {
  10. }
  11. public DbSet&lt;User&gt; Users { get; set; }
  12. public DbSet&lt;Tweet&gt; Tweets { get; set; }
  13. public DbSet&lt;Tag&gt; Tags { get; set; }
  14. public DbSet&lt;Like&gt; Likes { get; set; }
  15. public DbSet&lt;TwReply&gt; TwReplies { get; set; }
  16. protected override void OnModelCreating(ModelBuilder modelBuilder)
  17. {
  18. modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
  19. var relationships = modelBuilder.Model.GetEntityTypes()
  20. .SelectMany(e =&gt; e.GetForeignKeys());
  21. foreach (var relationship in relationships)
  22. {
  23. relationship.DeleteBehavior = DeleteBehavior.Restrict;
  24. }
  25. base.OnModelCreating(modelBuilder);
  26. }
  27. }
  28. }

There are 2 replies (3 and 10) for Tweet Id:1
but output is:

  1. {
  2. &quot;id&quot;: 1,
  3. &quot;user&quot;: {
  4. &quot;userName&quot;: &quot;asdasdasd&quot;,
  5. &quot;displayName&quot;: &quot;asdasdasd&quot;,
  6. &quot;profileImg&quot;: &quot;string&quot;
  7. },
  8. &quot;content&quot;: &quot;First tweet&quot;,
  9. &quot;createdAt&quot;: null,
  10. &quot;likeCount&quot;: 3,
  11. &quot;tags&quot;: [
  12. {
  13. &quot;name&quot;: &quot;#testingSeed1&quot;
  14. },
  15. {
  16. &quot;name&quot;: &quot;#testingSeed2&quot;
  17. },
  18. {
  19. &quot;name&quot;: &quot;#testing&quot;
  20. }
  21. ],
  22. &quot;replies&quot;: []
  23. }

我无法从数据库中获取.NET 7.0 Web API上的推文回复。

我无法从数据库中获取.NET 7.0 Web API上的推文回复。

I tried to get replies while getting a Tweet by Id but the program doesn't get Replies. I checked how does it work with breakpoints and it seems problem is in TweetRepository part. It returns nothing for Replies when it gets entity. I use Entity Framework Core BTW.

答案1

得分: 1

实体Tweet(简化版)如下所示:

  1. public class Tweet
  2. {
  3. public int Id { get; set; }
  4. public string Content { get; set; } = "";
  5. public ICollection<Tweet>? Replies { get; set; }
  6. }

然后,EF Core 将把这个模型映射到以下数据库模式:

  1. CREATE TABLE [Tweets] (
  2. [Id] int NOT NULL,
  3. [Content] nvarchar(max) NOT NULL,
  4. [TweetId] int NULL,
  5. CONSTRAINT [PK_Tweets] PRIMARY KEY ([Id]),
  6. CONSTRAINT [FK_Tweets_Tweets_TweetId] FOREIGN KEY ([TweetId]) REFERENCES [Tweets] ([Id])
  7. );

当没有指定数据库模式时,EF Core 使用约定来确定数据库模式。对于指向同一实体的集合导航属性,约定是一对多关系(一个推文可以有多个回复,但只能回复一个推文)。就像模型是这样的:

  1. public class Tweet
  2. {
  3. public int Id { get; set; }
  4. public string Content { get; set; } = "";
  5. public ICollection<Tweet>? Replies { get; set; }
  6. public Tweet ReplyTo { get; set; }
  7. }

您可以参考文档 EF Core:关系发现的约定 了解更多关于关系的约定信息。


在您的情况下,这是一个多对多关系(一个推文可以有多个回复,也可以回复多个推文),通过中间实体 TwReply

按照约定,模型将如下所示:

  1. public class Tweet
  2. {
  3. public int Id { get; set; }
  4. public string Content { get; set; } = "";
  5. public ICollection<TwReply>? Replies { get; set; }
  6. }
  7. public class TwReply
  8. {
  9. public int Id { get; set; }
  10. public Tweet Tweet { get; set; }
  11. public Tweet Reply { get; set; }
  12. }

如果您想保留您的模型,您需要手动指定关系,如下所示:

  1. protected override void OnModelCreating(ModelBuilder modelBuilder)
  2. {
  3. ...
  4. modelBuilder.Entity<Tweet>()
  5. .HasMany(t => t.Replies)
  6. .WithMany()
  7. .UsingEntity<TwReply>(
  8. i => i.HasOne(tr => tr.Reply).WithMany(),
  9. i => i.HasOne(tr => tr.Tweet).WithMany()
  10. );
  11. }
英文:

The entity Tweet (simplified) is :

  1. public class Tweet
  2. {
  3. public int Id { get; set; }
  4. public string Content { get; set; } = &quot;&quot;;
  5. public ICollection&lt;Tweet&gt;? Replies { get; set; }
  6. }

Then EF Core will tanlaste this model to this DB Schema :

  1. CREATE TABLE [Tweets] (
  2. [Id] int NOT NULL,
  3. [Content] nvarchar(max) NOT NULL,
  4. [TweetId] int NULL,
  5. CONSTRAINT [PK_Tweets] PRIMARY KEY ([Id]),
  6. CONSTRAINT [FK_Tweets_Tweets_TweetId] FOREIGN KEY ([TweetId]) REFERENCES [Tweets] ([Id])
  7. );

When the DB schema isn't specified, EF Core use convention to determine the DB schema. And the convention for a collection navigation property to the same entity is 1 to n (a tweet can have manyreplies, but can reply to only one tweet). It's like the model was :

  1. public class Tweet
  2. {
  3. public int Id { get; set; }
  4. public string Content { get; set; } = &quot;&quot;;
  5. public ICollection&lt;Tweet&gt;? Replies { get; set; }
  6. public Tweet ReplyTo { get; set; }
  7. }

You can refer to the documentatino EF Core : Conventions for relationship discovery for more information about the convention about relationship.


In you case, it's a relation n to n (a tweet can have many reply and can reply to many tweet) by the intermediate entity TwReply.

By convention, the model will be :

  1. public class Tweet
  2. {
  3. public int Id { get; set; }
  4. public string Content { get; set; } = &quot;&quot;;
  5. public ICollection&lt;TwReply&gt;? Replies { get; set; }
  6. }
  7. public class TwReply
  8. {
  9. public int Id { get; set; }
  10. public Tweet Tweet { get; set; }
  11. public Tweet Reply { get; set; }
  12. }

If you want keep your model, you need to specify manually the relation like :

  1. protected override void OnModelCreating(ModelBuilder modelBuilder)
  2. {
  3. ...
  4. modelBuilder.Entity&lt;Tweet&gt;()
  5. .HasMany(t =&gt; t.Replies)
  6. .WithMany()
  7. .UsingEntity&lt;TwReply&gt;(
  8. i =&gt; i.HasOne(tr =&gt; tr.Reply).WithMany(),
  9. i =&gt; i.HasOne(tr =&gt; tr.Tweet).WithMany()
  10. );
  11. }

huangapple
  • 本文由 发表于 2023年7月27日 17:14:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/76778218.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定