简体   繁体   English

如何使用 Entity Framework 在 .NET Core 中保存用户数据

[英]How to save user data in .NET Core with Entity Framework

I am working with .NET Core 2.2 and I am having trouble understanding the right way to save data owned by a user.我正在使用 .NET Core 2.2,但无法理解保存用户拥有的数据的正确方法。

I am using the out of the box identity scaffolding and code first migrations.我正在使用开箱即用的身份脚手架和代码优先迁移。 Users are stored in the AspNetUsers table and I'm leveraging Google/Facebook providers.用户存储在AspNetUsers表中,我正在利用 Google/Facebook 提供商。

As a basic example, if I have a simple model such as this, I can't find a clean example of how to reference the owner of the data in the model.作为一个基本的例子,如果我有一个像这样的简单模型,我找不到一个干净的例子来说明如何在模型中引用数据的所有者。

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??
}

Additionally, there seems to be a handful of ways to retrieve and store the user information as well:此外,似乎还有几种方法可以检索和存储用户信息:

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

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

Maybe I'm completely missing something obvious here, but I would love to see a very basic model and controller example that saves a record with the users identity value as a foreign key with a best practice approach.也许我在这里完全遗漏了一些明显的东西,但我很想看到一个非常基本的模型和控制器示例,它使用最佳实践方法将带有用户身份值的记录保存为外键。

Thanks!谢谢!

If in the model UserFavoriteColor you have defined both the foreign key field UserId and the navigation property User then you can choose which property to set.如果在模型UserFavoriteColor中定义了外键字段UserId导航属性User则可以选择要设置的属性。 I would use the ForeignKey DataAnnotation attribute to further describe the relationship between the two fields.我将使用ForeignKey DataAnnotation属性来进一步描述两个字段之间的关系。

If you only implemented the User navigation proerty in the model, then the Foreign Key field would still be implemented in the database level, but you would not be able to reference it in your code.如果您只在模型中实现了User导航属性,那么外键字段仍将在数据库级别实现,但您将无法在代码中引用它。 So it is not explicitly required and in many online examples we leave it out to simplify the example and because many would consider exposing the foreign key in the model as implementation detail that should not be there...所以它不是明确要求的,并且在许多在线示例中我们将其省略以简化示例,并且因为许多人会考虑将模型中外键公开为不应该存在的实现细节......

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        
}

To save a record of this type through a controller is pretty standard, generally through a controller I would set the Foreign Key field and not the Navigation Property .通过控制器保存这种类型的记录是非常标准的,通常通过控制器我会设置外键字段而不是导航属性 Its simpler code and less prone to duplicate entries being generated in the database.它的代码更简单,并且不太容易在数据库中生成重复的条目。

If you have a User object, you can set that instead of the UserId and the key field will be resolved for you automatically on save changes, but the User object MUST have been loaded from or at least attached to the same DbContext or it can result in a new User record being created in the database.如果您有一个User对象,您可以设置它而不是UserId并且键字段将在保存更改时自动为您解析,但User对象必须已从相同的DbContext加载或至少附加到相同的DbContext否则它可能会导致在数据库中创建的新User记录中。

To save a reference to the Current User then this is as good a reference as any , the mechanism that you use to retrieve the User Id is however highly dependent on how you have configured your authentication, which is out of scope for this question.要保存对当前用户的引用,那么这与任何引用一样好,但是您用来检索用户 ID的机制高度依赖于您配置身份验证的方式,这超出了本问题的范围。

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

Remember EF uses convention over configuration and uses it to identify primary keys, foreign keys and mappings记住EF 使用约定优于配置并使用它来标识主键、外键和映射

Lets consider this scenario (See inline comments)让我们考虑一下这种情况(见内嵌评论)

As per the default convention, EF makes a property as foreign key property when its name matches with the primary key property of a related entity.按照默认约定,当属性名称与相关实体的主键属性匹配时,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; }
}

To Override Foreign: Use this data annotation against the respective property in your Domain Class覆盖外部:针对域类中的相应属性使用此数据注释

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

[ForeignKey] annotation on the foreign key property in the dependent entity(as in the example above) [ForeignKey]依赖实体中外键属性的注解(如上例)
[ForeignKey] annotation on the navigation property in the dependent entity [ForeignKey]依赖实体中导航属性的注解
[ForeignKey] annotation on the navigation property in the principal entity [ForeignKey]主体实体中导航属性的注解


Now to add migrations and update database现在添加迁移和更新数据库

  • Add-Migration AddNewUser添加迁移添加新用户

Add a new user添加新用户

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更新数据库 -verbose

Note: Make sure you have good separation between Domain Classes and Data Model while you are beginning.注意:在开始时,请确保域类和数据模型之间有很好的分离。

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

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