WebApi создать и EF Inheritance - PullRequest
       6

WebApi создать и EF Inheritance

0 голосов
/ 12 сентября 2018

У меня есть следующие объекты:

abstract class User
{
    string Id 
    string Name 
}

class UserA: User
{
    string PropA
}

class UserB : User
{
    string PropB
}

Это хорошее решение - создать уникальное create (сообщение) с динамическим параметром и создать экземпляр подкласса в соответствии со свойством?

[HttpPost]
public IActionResult Create([FromBody]dynamic data)
{
    if (data.PROP == null)
    {
        _context.Users.Add(new UserA(data.PropA));
    }
    else
    {
        _context.Users.Add(new UserB(data.PropB));
    }

 ...

1 Ответ

0 голосов
/ 12 сентября 2018

Не используйте dynamic. Я на самом деле немного удивлен, что работает вообще. Хотя нет никаких признаков того, что вы действительно тестировали этот код, так что, возможно, это не так. Связыватель модели должен знать конкретный тип для привязки, чтобы он мог определить, как сопоставить значения с целевым экземпляром. Без сильных типов он ничего не может сделать, кроме как сделать все строкой, поскольку именно так оно и поступает в теле запроса.

В любом случае, для чего-то подобного правильный подход - использовать модель представления. Ваша модель представления должна содержать все свойства для всех возможных производных типов. Опять же, средство привязки модели нуждается в них, чтобы определить, как отобразить данные из тела запроса, поэтому, если свойство не существует, оно просто отбросит связанные данные.

Вот почему вы не можете просто использовать базовый класс. Если бы это был обычный метод, вы могли бы сделать что-то вроде:

public IActionResult Create([FromBody]User data)

Тогда внутри вы можете использовать сопоставление с образцом или подобное для приведения к правильному производному типу. Это работает, потому что в конечном итоге объект в памяти фактически будет экземпляром чего-то вроде UserA, и вы просто повышаете его до User. В результате вы всегда можете привести его обратно к UserA. Тем не менее, действия разные. Из запроса приходит , а не экземпляр объекта. Связыватель моделей служит для создания из него экземпляра объекта путем проверки параметра, с которым он должен связываться. Если этот параметр имеет тип User, то он заполнит свойства User и откажется от всего остального. В результате объект в памяти является просто User, и нет никакого способа привести к чему-то вроде UserA - по крайней мере с точки зрения наличия всех значений, которые были фактически отправлены для экземпляра UserA, находящегося на объект.

Что возвращает нас к представлению модели:

public class UserViewModel
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string PropA { get; set; }
    public string PropB { get; set; }
}

Тогда пусть ваше действие примет это как параметр:

public IActionResult Create([FromBody]UserViewModel data)

Тогда внутри:

if (!string.IsNullOrWhiteSpace(data.PropA))
{
    // UserA was posted, map data to an instance of UserA
}

Аналогично для UserB. Если хотите, вы также можете опубликовать явный «тип» вместе с данными и включить его, чтобы создать экземпляр правильного типа. Тебе решать. Чтобы уменьшить дублирование кода, вы можете создать экземпляр правильного типа, но сохранить его в переменной типа User. Затем, если вам нужно вернуться к правильному типу, вы можете использовать сопоставление с образцом:

User user;
switch (data.Type)
{
    case "UserA":
        user = new UserA
        {
            Id = data.Id,
            Name = data.Name,
            PropA = data.PropA
        };
        break;
     // etc.
     default:
         user = new User
         {
             Id = data.Id,
             Name = data.Name
         };
         break;
}

Потом позже:

switch (user)
{
    case UserA userA:
        // do something specific with `userA`
    // etc.
 }

Или:

if (user is UserA userA)
{
     // do something with `userA`
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...