我无法在.NET 7.0 Web API上从数据库获取Tweet回复

daolsyd0  于 2023-08-08  发布在  .NET
关注(0)|答案(1)|浏览(106)

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

using TwitterCloneApp.Core.Interfaces;

namespace TwitterCloneApp.Core.Models
{
    public class Tweet : IBaseEntity, IDeletable, IUpdatedAt, ICreatedAt
    {
        public int Id { get; set; }
        public int UserId { get; set; }
        public string Content { get; set; }
        public User User { get; set; }
        public bool isMainTweet { get; set; }
        public bool IsDeleted { get; set; } = false;
        public DateTime? DeletedAt { get; set; }
        public DateTime? UpdatedAt { get; set; }
        public DateTime? CreatedAt { get; set; }
        public ICollection<Tag>? Tags { get; set; } // Many-to-Many ilişkisi için koleksiyon
        public ICollection<Tweet>? Replies { get; set; }
        public ICollection<Like>? Likes { get; set; }
    }
}

字符串
TwReply.Cs(用于关系)

namespace TwitterCloneApp.Core.Models
{
    public class TwReply
    {
        public int TweetId { get; set; }
        public int ReplyId { get; set; }
        public Tweet Tweet { get; set; }
        public Tweet Reply { get; set; }
    }
}


TweetDto.cs

using TwitterCloneApp.DTO.Tag;
using TwitterCloneApp.DTO.User;

namespace TwitterCloneApp.DTO.Tweet
{
    public class TweetDto
    {
        public int Id { get; set; }
        public UserResponseDto User { get; set; }
        public string? Content { get; set; }
        public DateTime? CreatedAt { get; set; }
        public int LikeCount { get; set; }
        public List<TagResponseDto>? Tags { get; set; }
        public List<ReplyResponseDto>? Replies { get; set; }
    }
}


ReplyResponseDto.cs

using TwitterCloneApp.DTO.User;

namespace TwitterCloneApp.DTO.Tweet
{
    public class ReplyResponseDto
    {
        public UserResponseDto User { get; set; }
        public string Content { get; set; }
        public DateTime? CreatedAt { get; set; }
        public int LikeCount { get; set; }
    }
}


UserResponseDto.cs

namespace TwitterCloneApp.DTO.User
{
    public class UserResponseDto
    {
        public string UserName { get; set; }
        public string DisplayName { get; set; }
        public string? ProfileImg { get; set; }
    }
}


TweetController部件

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


Tweet服务部分

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


TweetRepository部分

public async Task<TweetDto> GetTweetWithTagsByIdAsync(int tweetId)
{
    var tweet = await _tweet.Include(t => t.Tags)
                            .Include(t => t.Replies).ThenInclude(reply => reply.User)
                            .Include(t => t.User)
                            .Include(t => t.Likes)
                            .FirstOrDefaultAsync(t => t.Id == tweetId);

    if (tweet == null)
    {
        return null; // veya gerekli işlemleri yapın
    }

    var tweetDto = new TweetDto
    {
        Id = tweet.Id,
        Content = tweet.Content,
        CreatedAt = tweet.CreatedAt,
        LikeCount = tweet.Likes?.Count ?? 0,
        Tags = tweet.Tags?.Select(t => new TagResponseDto
        {
            Name = t.Name
        }).ToList(),
        User = new UserResponseDto
        {
            UserName = tweet.User.UserName,
            DisplayName = tweet.User.DisplayName,
            ProfileImg = tweet.User.ProfileImg
        },
        Replies = tweet.Replies?.Select(reply => new ReplyResponseDto
        {
            User = new UserResponseDto
            {
                UserName = reply.User.UserName,
                DisplayName = reply.User.DisplayName,
                ProfileImg = reply.User.ProfileImg
            },
            Content = reply.Content,
            CreatedAt = reply.CreatedAt,
            LikeCount = reply.Likes?.Count ?? 0
        }).ToList()
    };

    return tweetDto;
}


AppDbContext.cs

using Microsoft.EntityFrameworkCore;
using System.Reflection;
using TwitterCloneApp.Core.Models;

namespace TwitterCloneApp.Repository
{
    public class AppDbContext : DbContext
    {
        public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
        { 
        }
        public DbSet<User> Users { get; set; }
        public DbSet<Tweet> Tweets { get; set; }
        public DbSet<Tag> Tags { get; set; }
        public DbSet<Like> Likes { get; set; }
        public DbSet<TwReply> TwReplies { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
            
            var relationships = modelBuilder.Model.GetEntityTypes()
                .SelectMany(e => e.GetForeignKeys());

            foreach (var relationship in relationships)
            {
                relationship.DeleteBehavior = DeleteBehavior.Restrict;
            }
            base.OnModelCreating(modelBuilder);
        }

    }
}


Tweet Id:1有2个回复(3和10),但输出为:

{
  "id": 1,
  "user": {
    "userName": "asdasdasd",
    "displayName": "asdasdasd",
    "profileImg": "string"
  },
  "content": "First tweet",
  "createdAt": null,
  "likeCount": 3,
  "tags": [
    {
      "name": "#testingSeed1"
    },
    {
      "name": "#testingSeed2"
    },
    {
      "name": "#testing"
    }
  ],
  "replies": []
}


的数据



我试图得到答复,而得到一个推文的ID,但该程序不得到答复。我检查了它是如何与断点工作的,似乎问题是在TweetRepository部分。当它得到实体时,它不返回任何Replies。使用Entity Framework Core BTW。

vc9ivgsu

vc9ivgsu1#

实体Tweet(简化)为:

public class Tweet
{
    public int Id { get; set; }
    public string Content { get; set; } = "";
    public ICollection<Tweet>? Replies { get; set; }
}

字符串
然后EF Core将把这个模型转换到这个DB Schema:

CREATE TABLE [Tweets] (
    [Id] int NOT NULL,
    [Content] nvarchar(max) NOT NULL,
    [TweetId] int NULL,
    CONSTRAINT [PK_Tweets] PRIMARY KEY ([Id]),
    CONSTRAINT [FK_Tweets_Tweets_TweetId] FOREIGN KEY ([TweetId]) REFERENCES [Tweets] ([Id])
);


当没有指定DB模式时,EF Core使用约定来确定DB模式。对于同一个实体,集合导航属性的约定是1到n(一条tweet可以有许多回复,但只能回复一条tweet)。就像这个模型:

public class Tweet
{
    public int Id { get; set; }
    public string Content { get; set; } = "";
    public ICollection<Tweet>? Replies { get; set; }
    public Tweet ReplyTo { get; set; }
}


有关关系约定的更多信息,请参阅文档EF Core : Conventions for relationship discovery
在你的例子中,它是中间实体TwReply的n到n的关系(一条tweet可以有很多回复,也可以回复很多tweet)。
按照惯例,模型将是:

public class Tweet
{
    public int Id { get; set; }
    public string Content { get; set; } = "";
    public ICollection<TwReply>? Replies { get; set; }
}

public class TwReply
{
    public int Id { get; set; }
    public Tweet Tweet { get; set; }
    public Tweet Reply { get; set; }
}


如果你想保留你的模型,你需要手动指定关系,如:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    ...
    modelBuilder.Entity<Tweet>()
        .HasMany(t => t.Replies)
        .WithMany()
        .UsingEntity<TwReply>(
            i => i.HasOne(tr => tr.Reply).WithMany(),
            i => i.HasOne(tr => tr.Tweet).WithMany()
        );
}

相关问题