简体   繁体   English

具有外键关系的ASP.NET Core Web API和EF Core模型

[英]ASP.NET Core Web API & EF Core Models with Foreign Key relationship

I'm developing a basic Web API project for education purposes, and I am having trouble with my EF Model relationships. 我正在开发一个用于教育目的的基本Web API项目,而我的EF模型关系遇到了麻烦。 I have 2 models. 我有2个模型。 Message and MessageBoard . MessageMessageBoard

public class Message
    {
        public long Id { get; set; }
        public string Text { get; set; }
        public string User { get; set; }
        public DateTime PostedDate { get; set; }

        public long MessageBoardId { get; set; }
        [ForeignKey("MessageBoardId")]
        public MessageBoard MessageBoard { get; set; }
    }

public class MessageBoard
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }

        public ICollection<Message> Messages { get; set; }
    }

I've setup my DBContext and created a migration to configure the database. 我已经设置了DBContext并创建了迁移以配置数据库。 I generated two Web API controllers using EF Scaffolding. 我使用EF脚手架生成了两个Web API控制器。 The migration appears to correctly detect the relationship between the two models: 迁移似乎可以正确检测两个模型之间的关系:

modelBuilder.Entity("Asp.net_Core_Web_Api.Models.Message", b =>
{
   b.HasOne("Asp.net_Core_Web_Api.Models.MessageBoard", "MessageBoard")
   .WithMany("Messages")
   .HasForeignKey("MessageBoardId")
   .OnDelete(DeleteBehavior.Cascade);
});

But, when I create a MessageBoard and then create a Message with the ID of the MessageBoard, they don't appear to link correctly. 但是,当我创建一个MessageBoard然后创建一个带有MessageBoard ID的Message时,它们似乎无法正确链接。 In PostMan, I am doing the following: 在PostMan中,我正在执行以下操作:

1) Post a new MessageBoard 1)发布一个新的留言板

POST - https://localhost:44384/api/MessageBoards/

Body - Raw - Json

{
 "Name":"Test Board",
 "Description":"A Message board for testing purposes."
}

Returns 返回

{
    "id": 4,
    "name": "Test Board",
    "description": "A Message board for testing purposes.",
    "messages": null
}

2) Post a new Message 2)发表新讯息

POST - https://localhost:44384/api/Messages

Body - Raw - JSON

{
    "Text":"Posting my first message!",
    "User":"Jesse",
    "PostedDate":"1/1/2019",

    "MessageBoardId":4
}

Returns 返回

{
    "id": 2,
    "text": "Posting my first message!",
    "user": "Jesse",
    "postedDate": "2019-01-01T00:00:00",
    "messageBoardId": 4,
    "messageBoard": null
}

I would expect that the messageBoard would not be null, and it would instead return the JSON for the messageBoard that was previously created. 我希望messageBoard不会为null,而是返回先前创建的messageBoard的JSON。 If I change to a GET method, it is also null. 如果更改为GET方法,则它也为null。 Why is it null? 为什么它为空?

EDIT: Here are my controllers. 编辑:这是我的控制器。 I removed actions except for GET and POST. 我删除了除GET和POST之外的操作。

[Route("api/[controller]")]
[ApiController]
public class MessageBoardsController : ControllerBase
{
        private readonly MessageBoardContext _context;

        public MessageBoardsController(MessageBoardContext context)
        {
            _context = context;
        }

        // GET: api/MessageBoards/5
        [HttpGet("{id}")]
        public async Task<ActionResult<MessageBoard>> GetMessageBoard(long id)
        {
            var messageBoard = await _context.MessageBoards.FindAsync(id);

            if (messageBoard == null)
            {
                return NotFound();
            }

            return messageBoard;
        }


        // POST: api/MessageBoards
        [HttpPost]
        public async Task<ActionResult<MessageBoard>> PostMessageBoard(MessageBoard messageBoard)
        {
            _context.MessageBoards.Add(messageBoard);
            await _context.SaveChangesAsync();

            return CreatedAtAction("GetMessageBoard", new { id = messageBoard.Id }, messageBoard);
        }
}


[Route("api/[controller]")]
[ApiController]
public class MessagesController : ControllerBase
{
        private readonly MessageBoardContext _context;

        public MessagesController(MessageBoardContext context)
        {
            _context = context;
        }

        // GET: api/Messages/5
        [HttpGet("{id}")]
        public async Task<ActionResult<Message>> GetMessage(long id)
        {
            var message = await _context.Messages.FindAsync(id);

            if (message == null)
            {
                return NotFound();
            }

            return message;
        }


        // POST: api/Messages
        [HttpPost]
        public async Task<ActionResult<Message>> PostMessage(Message message)
        {
            _context.Messages.Add(message);
            await _context.SaveChangesAsync();

            return CreatedAtAction("GetMessage", new { id = message.Id }, message);
        }
}

I would expect that the messageBoard would not be null, and it would instead return the JSON for the messageBoard that was previously created. 我希望messageBoard不会为null,而是返回先前创建的messageBoard的JSON。 If I change to a GET method, it is also null. 如果更改为GET方法,则它也为null。 Why is it null? 为什么它为空?

This is because you are returning the newly created message, here only MessageBoadId is exists, not MessageBoad object. 这是因为你正在返回新创建的消息,这里只MessageBoadId是存在的,不是MessageBoad对象。 So you have to load the related MessageBoad from database using Include for newly created message. 因此,您必须使用Include为新创建的消息从数据库加载相关的MessageBoad

Your PostMessage method should be as follows: 您的PostMessage方法应如下所示:

// POST: api/Messages
[HttpPost]
public async Task<ActionResult<Message>> PostMessage(Message message)
{
    _context.Messages.Add(message);
    await _context.SaveChangesAsync();

    var message = await _context.Messages
                    .Include(i=>i.MessageBoard)
                    .FirstOrDefaultAsync(i => i.Id == message.Id);

    return Json(message);
}

You need to load related data 您需要加载相关数据

So for example, for your MessageBoard GET - // GET: api/MessageBoards/5 例如,对于您的MessageBoard GET- // GET: api/MessageBoards/5

Change from: 更改自:

var messageBoard = await _context.MessageBoards.FindAsync(id);

To

var messageBoard = await _context.MessageBoards
                        .Include(i=>i.Messages)
                        .FirstOrDefaultAsync(i => i.Id == id);

You've given the the application output and what the database looks like, but not the middle bit on how it saves/retrieves the data. 您已经给出了应用程序的输出以及数据库的外观,但是没有给出如何保存/检索数据的中间内容。 Without knowing what's going on in the middle, my best stab in the dark is that you've neither set your lazy loading correctly nor used Include to include the MessageBoard entity. 在不知道中间发生了什么的情况下,我最好的解决方法是既没有正确设置延迟加载,也没有使用Include来包含MessageBoard实体。

More info here on what they are. 有关它们的详细信息,请点击此处

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM