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

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

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

问题

我正在制作一个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);
}

TweetService部分

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; // 或者执行必要的操作
	}

	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);
        }

    }
}

推文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": []
}

我尝试在获取推文时获取回复,但程序不会获取回复。我使用的是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

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&lt;Tag&gt;? Tags { get; set; } // Many-to-Many ilişkisi i&#231;in koleksiyon
		public ICollection&lt;Tweet&gt;? Replies { get; set; }
		public ICollection&lt;Like&gt;? Likes { get; set; }
    }
}

TwReply.Cs (for relation)

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&lt;TagResponseDto&gt;? Tags { get; set; }
        public List&lt;ReplyResponseDto&gt;? 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 part

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

TweetService part

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

TweetRepository part

public async Task&lt;TweetDto&gt; GetTweetWithTagsByIdAsync(int tweetId)
{
	var tweet = await _tweet.Include(t =&gt; t.Tags)
							.Include(t =&gt; t.Replies).ThenInclude(reply =&gt; reply.User)
							.Include(t =&gt; t.User)
							.Include(t =&gt; t.Likes)
							.FirstOrDefaultAsync(t =&gt; 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 =&gt; 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 =&gt; 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&lt;AppDbContext&gt; options) : base(options)
        { 
        }
        public DbSet&lt;User&gt; Users { get; set; }
        public DbSet&lt;Tweet&gt; Tweets { get; set; }
        public DbSet&lt;Tag&gt; Tags { get; set; }
        public DbSet&lt;Like&gt; Likes { get; set; }
        public DbSet&lt;TwReply&gt; TwReplies { get; set; }

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

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

    }
}

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

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

我无法从数据库中获取.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(简化版)如下所示:

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

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

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])
);

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

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:关系发现的约定 了解更多关于关系的约定信息。


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

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

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()
        );
}
英文:

The entity Tweet (simplified) is :

public class Tweet
{
    public int Id { get; set; }
    public string Content { get; set; } = &quot;&quot;;
    public ICollection&lt;Tweet&gt;? Replies { get; set; }
}

Then EF Core will tanlaste this model to this 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])
);

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 :

public class Tweet
{
    public int Id { get; set; }
    public string Content { get; set; } = &quot;&quot;;
    public ICollection&lt;Tweet&gt;? Replies { get; set; }
    public Tweet ReplyTo { get; set; }
}

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 :

public class Tweet
{
    public int Id { get; set; }
    public string Content { get; set; } = &quot;&quot;;
    public ICollection&lt;TwReply&gt;? Replies { get; set; }
}

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

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

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

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:

确定