具有自有财产的种子实体

时间:2018-06-14 16:58:15

标签: c# entity-framework-core ef-core-2.1

我正在尝试在我的数据库中播种用户实体。 User实体具有owend属性EmailPermissions

当我运行命令

  

dotnet ef迁移添加Initial;

我收到错误

  

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

但由于EmailPermissions是一个拥有的实体,我没有给它一个明确的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
        });
}   

如果我从构造函数中删除EmailPermissions属性的实例化,我会收到以下错误

  

“User”类型的实体正在与“EmailPermissions”类型的实体共享“AspNetUsers”表,但没有此类型的实体具有标记为“已添加”的相同键值。

如果用户拥有自有属性,我如何通过.HasData方法为用户播种?

5 个答案:

答案 0 :(得分:9)

目前,文档中缺少此信息(由#710: Document how to seed owned types跟踪)。 EF Core团队(带示例)在#12004: Problem seeding data that contains owned type主题中解释了它:

  

var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest; var xhr = new XMLHttpRequest(); xhr.open("POST", '/connect/token', true); //Send the proper header information along with the request xhr.setRequestHeader("Host", "name.of.host"); xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xhr.setRequestHeader("Cache-Control", "no-cache"); xhr.onreadystatechange = function() { // Call a function when the state changes. if (xhr.readyState == XMLHttpRequest.DONE && xhr.status == 200) { // Request finished. Do processing here. console.log(xhr.responseText); } } xhr.send("client-id=guid&grant_type=refresh_token&refresh_token=tokenstuff"); 电话结束后,必须使用HasData来拨打自有类型。此外,由于按惯例拥有的类型具有在阴影状态下生成的主键,并且由于种子数据需要定义键,因此这需要使用匿名类型并设置密钥。

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

根据建议,您应该从构造函数中删除OwnsOne属性的实例化,并添加如下的种子代码:

EmailPermissions

由于需要知道影子PK名称和匿名类型的使用,因此相当烦人且容易出错。正如同一成员提到的那样

  

请注意,如果播种支持导航,则此操作会变得更加容易,#10000: Data Seeding: Add support for navigations

跟踪

答案 1 :(得分:1)

感谢Ivan Stoev的回答。我添加了更多的代码以易于想象。 这是基于示例的种子数据功能代码。

  • 首先添加用户数据。
  • 之后,添加拥有对象的数据。
  • 拥有对象的数据必须是匿名的,因为PK会请求。该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
        });
    });
}

答案 2 :(得分:0)

如果要避免使用匿名类型来指定阴影属性键,则可以在模型类中显式声明它们,并使用Fluent API作为键来配置它们。这样,您不必猜测属性名称,而且不那么容易出错。

  

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

答案 3 :(得分:0)

在我的方案中,我希望在父类中自动初始化owner-type属性:

public class User
{
  EmailPermissions _EmailPermissions;
  public EmailPermissions 
  {
    get => _EmailPermissions ??= new EmailPermissions();
    set => _EmailPermissions = value;
  }
}

当我尝试添加种子数据时,我遇到了一个令人讨厌的异常。

解决方案是在其User调用中将 HasData 作为匿名类型传递。

答案 4 :(得分:0)

在启动时,我也遇到了同样的问题。 Here is the link to the github issue.