【问题标题】:How to save user data in .NET Core with Entity Framework如何使用 Entity Framework 在 .NET Core 中保存用户数据
【发布时间】:2020-03-08 03:23:30
【问题描述】:

我正在使用 .NET Core 2.2,但我无法理解保存用户拥有的数据的正确方法。

我正在使用开箱即用的身份脚手架和代码优先迁移。 用户存储在AspNetUsers 表中,我正在利用 Google/Facebook 提供商。

作为一个基本的例子,如果我有一个像这样的简单模型,我找不到一个干净的例子来说明如何在模型中引用数据的所有者。

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# entity-framework .net-core entity-framework-core


【解决方案1】:

如果在模型UserFavoriteColor 中定义了外键字段UserId导航属性 User,那么您可以选择设置哪个属性.我会使用ForeignKey DataAnnotation 属性来进一步描述这两个字段之间的关系。

如果您只在模型中实现了User 导航属性,那么 外键 字段仍将在数据库级别实现,但您将无法在代码中引用它.所以它不是明确要求的,在许多在线示例中,我们将其省略以简化示例,因为许多人会考虑在 model 中公开 外键 作为实现细节,应该不在……

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        
}

通过控制器保存这种类型的记录是相当标准的,通常通过控制器我会设置外键字段而不是导航属性。 它的代码更简单,更不容易在数据库中生成重复条目。

如果您有 User 对象,您可以设置它而不是 UserId,并且在保存更改时会自动为您解析关键字段,但 User 对象必须已从相同的DbContext加载或至少附加到相同的DbContext,否则可能会导致在数据库中创建新的User记录。

要保存对 Current User 然后 this is as good a reference as any 的引用,您用来检索 User 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();

【讨论】:

  • 优秀。我已经在您的示例中将外键结构用于其他领域,并且倾向于使用它,但只是找不到它的琐碎文档以确保它适用于像身份这样敏感的东西。感谢您的详细撰写和解释!
【解决方案2】:

记住 EF 使用convention over configuration 并用它来识别主键、外键和映射

让我们考虑这种情况(参见内联 cmets)

根据默认约定,EF 将属性作为外键 当其名称与 a 的主键属性匹配时的属性 相关实体。

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]注解主要实体


现在添加迁移和更新数据库

  • 添加迁移 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
}
  • 更新数据库-详细

注意:确保在开始时域类和数据模型之间有良好的分离。

【讨论】:

  • 我已经看到其他文档创建了一个类似于您的示例的“IdentityUser”类,但是您不应该使用内置的而不是尝试使用包装器吗?克里斯的回答似乎更有意义,不需要定义“IdentityUser”(除非我误解了你的例子)。感谢您的报道。
  • @EricLongstreet,“使用内置而不是使用包装器”是什么意思
  • 在您的示例中,您定义了类模型“IdentityUser”,但是,据我了解,这是一个内置的 dotnet 核心身份脚手架类。 docs.microsoft.com/en-us/dotnet/api/…
  • 嗯好的,是的,你可以在上面使用内置脚手架,这里的重点是注意EF核心默认如何确定ForeignKey实体以及如何覆盖它们
  • 此外,没有必要将 id 标记为主键,因为这是由 EF Cores 约定推断的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-13
  • 2019-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-07
  • 1970-01-01
相关资源
最近更新 更多