代码之家  ›  专栏  ›  技术社区  ›  Mathieu VIALES Pavel

拥有财产的种子实体

  •  6
  • Mathieu VIALES Pavel  · 技术社区  · 7 年前

    我正在尝试在我的数据库中植入一个用户实体。这个 User 实体具有owend属性 EmailPermissions .

    当我运行命令时

    dotnet ef迁移添加初始值;

    我明白错误

    无法添加实体类型“user”的种子实体,因为它设置了导航“emailpermissions”。要种子关系,您需要将相关实体种子添加到“emailpermissions”并指定外键值{'userid'}。

    但自从 电子邮件权限 是一个拥有的实体我没有给它一个明确的 UserId 属性,这意味着我不能在数据库中单独播种。

    实体

    public sealed class User : IdentityUser
    {
        public User()
        {
            EmailPermissions = new EmailPermissions();
        }
    
        /* [..] */
    
        public string TemporaryEmailBeforeChange { get; set; }
        public bool IsEmailAwaitingUpdate { get; set; }
        public EmailPermissions EmailPermissions { get; set; }
        public ICollection<Registeration> Registerations { get; set; }
    
        /* [..] */
    
    }
    
    [Owned]
    public class EmailPermissions
    {
        /* [..] */
    
        public bool Newsletter { get; set; }
        public bool PromotionalOffers { get; set; }
        public bool PrestationReminders { get; set; }
        public bool PrestationOffers { get; set; }
    }
    

    播种呼叫

    private void SeedUser(ModelBuilder builder)
    {
        builder.Entity<User>().HasData(
            new User
            {
                Id = "37846734-172e-4149-8cec-6f43d1eb3f60",
                Email = "foo@foo.foo",
                UserName = "foo@foo.foo",
                PasswordHash = "AQAAAAEAACcQAAAAEIytBES+jqKH9jfuY3wzKyduDZruyHMGE6P+ODe1pSKM7BuGjd3AIe6RGRHrXidRsg==",
                SecurityStamp = "WR6VVAGISJYOZQ3W7LGB53EGNXCWB5MS",
                ConcurrencyStamp = "c470e139-5880-4002-8844-ed72ba7b4b80",
                EmailConfirmed = true
            });
    }   
    

    如果我移除 电子邮件权限 从构造函数中获取的属性我改为获取以下错误

    “user”类型的实体正在与“emailpermissions”类型的实体共享表“aspnetusers”,但没有此类型的实体具有标记为“added”的相同键值。

    如何通过 .HasData 方法当它有自己的财产?

    2 回复  |  直到 7 年前
        1
  •  15
  •   Ivan Stoev    7 年前

    当前文档中缺少此信息(跟踪者 #710: Document how to seed owned types )。这是由英孚核心团队(举例)在 #12004: Problem seeding data that contains owned type 线程:

    拥有的类型必须以 HasData OwnsOne 打电话。此外,由于按约定拥有的类型具有在阴影状态下生成的主键,并且由于种子数据需要定义键,因此这需要使用匿名类型并设置键。

    这基本上就是异常消息告诉你的。

    按照建议,您应该移除 EmailPermissions 属性,并添加如下种子设定代码:

    builder.Entity<User>().OwnsOne(e => e.EmailPermissions).HasData(
        new
        {
            UserId = "37846734-172e-4149-8cec-6f43d1eb3f60",
            // other properties ...
        }
    );
    

    由于需要知道shadow pk的名称和匿名类型的用法,所以非常烦人并且容易出错。如同一成员所述

    请注意,如果导航支持种子设定(由 #10000: Data Seeding: Add support for navigations

        2
  •  2
  •   Long Pham    5 年前

    谢谢伊万·斯托夫的回答。我添加了更多的代码以便于想象。 这是基于实例的种子数据函数代码。

    • 首先添加用户的数据。
    • 然后添加所属对象的数据。
    • 拥有对象的数据必须是匿名的,因为pk将请求。此主键不会出现在数据库中。名称应为实体名+ID

    示例:实体xxx=>pk将是xxxid

    private void SeedUser(ModelBuilder builder)
    {
        builder.Entity<User>(b =>
        {
            b.HasData(new User
            {
                Id = "37846734-172e-4149-8cec-6f43d1eb3f60",
                Email = "foo@foo.foo",
                UserName = "foo@foo.foo",
                // more properties of User
            });
            b.OwnsOne(e => e.EmailPermissions).HasData(new 
            {
                    UserId = "37846734-172e-4149-8cec-6f43d1eb3f60",
                    Newsletter = true,
                    PromotionalOffers = true,
                    PrestationReminders = true,
                    PrestationOffers = true
            });
        });
    }
    
        3
  •  1
  •   Shadow    6 年前

    如果要避免使用匿名类型来指定shadow属性键,可以在模型类中显式声明它们,并使用fluent api将它们配置为键。这样就不必猜测属性名,而且不容易出错。

    如果提供给property方法的名称与现有属性(shadow属性或实体类上定义的属性)的名称匹配,则代码将配置该现有属性,而不是引入新的shadow属性。 Source

    推荐文章