Как сохранить пользовательские данные в. NET Core с Entity Framework - PullRequest
2 голосов
/ 08 марта 2020

Я работаю с. NET Core 2.2, и у меня возникают проблемы с пониманием правильного способа сохранения данных, принадлежащих пользователю.

Я использую готовые леса идентификации и код первой миграции , Пользователи хранятся в таблице AspNetUsers, и я использую провайдеров Google / Facebook.

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

public class UserFavoriteColor
{
    public int Id { get; set; }
    public string Color {get; set;

    public IdentityUser User { get; set; }    // I've seen this in some documentation
    public string UserId { get; set; }        // I've seen this as well
    // Other ways??
}

Кроме того, существует несколько способов получения и хранения пользовательской информации:

// one way to get the id
User.FindFirst(ClaimTypes.NameIdentifier).Value;                   

// another way
 _userManager = MockUserManager.GetUserManager<ApplicationUser>(); 

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

Спасибо!

Ответы [ 2 ]

1 голос
/ 08 марта 2020

Если в модели UserFavoriteColor вы определили как поле внешнего ключа UserId, так и свойство навигации User, то вы можете выбрать какое свойство установить. Я бы использовал атрибут ForeignKey DataAnnotation для дальнейшего описания взаимосвязи между двумя полями.

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

public class UserFavoriteColor
{
    [Key]
    public int Id { get; set; }
    public string Color {get; set;

    [ForeignKey(nameof(UserId))]
    public virtual IdentityUser User { get; set; } // Navigation Property
    public string UserId { get; set; }     // ForeignKey Field        
}

Сохранить запись этого типа через контроллер довольно стандартно, обычно через контроллер я бы установил поле Foreign Key , а не Свойство навигации . Его более простой код и он менее подвержен дублированию записей, генерируемых в базе данных.

Если у вас есть объект User, вы можете установить его вместо UserId, и поле ключа будет разрешено для вас автоматически при сохранении изменений, но объект User ДОЛЖЕН загружен из или хотя бы присоединен к тому же DbContext , или это может привести к созданию новой записи User в база данных.

Чтобы сохранить ссылку на Текущий пользователь , затем , это такая же хорошая ссылка, как и любой , механизм, который вы используете для получения пользователя Идентификатор , однако, сильно зависит от того, как вы настроили аутентификацию, что выходит за рамки этого вопроса.

var currentUserId = User.FindFirst(ClaimTypes.NameIdentifier).Value;
var color = "Red";
...
// Insert a new favorite colour record
UserFavoriteColor record = new UserFavoriteColor {
    Color = color,
    UserId = currentUserId 
};
context.Add(record);
context.SaveChanges();

0 голосов
/ 08 марта 2020

Помните EF использует соглашение по конфигурации и использует его для идентификации первичных ключей, внешних ключей и сопоставлений

Давайте рассмотрим этот сценарий (см. Встроенные комментарии)

В соответствии с соглашением по умолчанию EF создает свойство как свойство внешнего ключа, когда его имя совпадает со свойством первичного ключа связанной сущности.

public class UserFavoriteColor
{
  public int Id { get; set; }
  public string Color {get; set;


  public int UserId { get; set; } // By default convention EF will mark this as foreign key property as its name matches the primary key of related entity
  public IdentityUser User { get; set; } // Navigation property 

}

public class IdentityUser
{
  public int UserId { get; set; } // EF will treat this as Primary Key 
  public string UserName {get; set;}
  public ICollection<UserFavoriteColor> FavColors { get; set; }
}

Для переопределения внешнего: Используйте эту аннотацию данных для соответствующего свойства в вашем доменном классе

[ForeignKey("IdentityUser")]
public int ThisUserId { get; set; }
public IdentityUser User { get; set; } 

[ForeignKey] аннотацию для свойства внешнего ключа в зависимом объекте (как в примере выше)
[ForeignKey] аннотация к свойству навигации в зависимом объекте
[ForeignKey] аннотация к свойству навигации в главном объекте


Теперь для добавления миграций и обновления базы данных

  • Add-Migration AddNewUser

Добавить нового пользователя

var color1 = new UserFavoriteColor {Color="Red"}
var user = new IdentityUser {UserName="Bob",};
using  (var context = new DbContext())
{
    context.DBSetName.Add(user);  
    context.SaveChanges();
    //Save changes will - Examine each object context is tracking
                        - Read state of object (state=new) therefore needs to Insert
                        - Emit SQL commands
                        - Execute SQL commands
                        - Captures any results
}
  • Update-Database -verbose

Примечание: Убедитесь, что у вас есть хорошее разделение между классами домена и моделью данных, когда вы начинаете.

...