【问题标题】:Seeding data with Foriegn Keys in a Migration在迁移中使用外键播种数据
【发布时间】:2019-11-22 05:26:14
【问题描述】:

我已获得需要导入数据库的时区数据。

我所做的是读取我的数据,格式为:

 List<string> items = new List<string>();
            items.Add("AF|Afghanistan|Asia/Kabul|UTC +04:30");
            items.Add("AX|Aland Islands|Europe/Mariehamn|UTC +02:00");
            items.Add("AL|Albania|Europe/Tirane|UTC +01:00");
            items.Add("DZ|Algeria|Africa/Algiers|UTC +01:00");
            items.Add("AS|American Samoa|Pacific/Pago_Pago|UTC -11:00");
            items.Add("AD|Andorra|Europe/Andorra|UTC +01:00");
            items.Add("AO|Angola|Africa/Luanda|UTC +01:00");
            items.Add("AI|Anguilla|America/Anguilla|UTC -04:00");
            items.Add("AQ|Antarctica|Antarctica/Casey|UTC +08:00");
            items.Add("AQ|Antarctica|Antarctica/Davis|UTC +07:00");
            items.Add("AQ|Antarctica|Antarctica/DumontDUrville|UTC +10:00");
            items.Add("AQ|Antarctica|Antarctica/Mawson|UTC +05:00");
            items.Add("AQ|Antarctica|Antarctica/McMurdo|UTC +13:00");
            items.Add("AQ|Antarctica|Antarctica/Palmer|UTC -03:00");

所以,一个国家可以有多个时区。

我有两个实体需要进入:

[Table("Country", Schema = "ref")]
public class Country
{
    [Key, Required]
    public int Id { get; set; }

    [Required, MaxLength(2)]
    public string Code { get; set; }

    [Required]
    public string Description { get; set; }


}

public class Timezone
{
    [Key, Required]
    public int Id { get; set; }

    [Required]
    public Country Country { get; set; }

    [Required]
    public string Description { get; set; }

    [Required]
    public int GMTOffset { get; set; }

    [ForeignKey("Country")]
    public int CountryId { get; set; }
}

我正在做的是浏览列表,并添加所有国家/地区。

  var timezoneData = data.Timezone.getData();
            //var countries = new List<Country>();
            List<ExistingObject> exists = new List<ExistingObject>();
            int countryId = 1;
            foreach (var item in timezoneData)
            {
                var splitup = item.Split('|');
                if (exists.Any(x => x.Name == splitup[1]))
                {

                    var c = new Country
                    {
                        Code = splitup[0],
                        Description = splitup[1],
                        Id = countryId
                    };

                modelBuilder.Entity<Country>().HasData(new Country[] { c });

                    countryId++;
                    exists.Add(new ExistingObject
                    {
                        Name = splitup[1],
                        Id = countryId,
                    });
                }
            }

然后,我需要添加所有时区。但是,因为 Timezone 有一个 Country(Id),所以我很难在 modelBuilder 中处理这种外键关系。我希望我可以像这样分配 FK 值(注意,为了简单起见,我现在是硬编码 CountryID 10)

将 Country 对象分配给 timezone.Country 会很好,但它似乎还不可用。所以我试图提供我分配给 Country 对象的 CountryID 值。 (注意,现在硬编码 10)

            foreach (var item in timezoneData)
            {
                int timezoneId = 1;
                var splitup = item.Split('|');
                modelBuilder.Entity<Timezone>().HasData(new Timezone[] { new Timezone
                {
                    Id = timezoneId,
                    CountryId = 10,
                    Description = splitup[2],
                    GMTOffset = 1
                } });

            }

但是,当我创建迁移时,它会产生错误:

无法添加实体类型“时区”的种子实体,因为已经添加了另一个具有与 {'Id'} 相同键值的种子实体。考虑使用“DbContextOptionsBuilder.EnableSensitiveDataLogging”来查看冲突的键值。

创建并执行 SQL 语句可能更容易,但这似乎与迁移无关。有没有办法实现我想要做的事情,并让迁移负责添加我的参考数据,这具有 FK 的复杂性?

【问题讨论】:

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


    【解决方案1】:

    处理时区是编程中最麻烦的部分之一。一般你尽量留在as far away from manually handling them as you can。 “这条路是疯狂的。”一点都不夸张。

    在 .NET 中使用时区时,您拥有最完整的 BlackBox 之一 - Windows。

    1. 始终存储、检索和传输 UTC 日期时间。使用本地时区通常是显示方面的问题。
    2. 切勿以字符串形式存储、检索或传输
    3. 如果你不能遵循规则 2,至少选择一个固定的编码和文化格式。现有的序列化方法往往会为您完成这部分工作。
    4. ToString() 能够在输出期间使用本地时区。它为此使用了 Windows 的完整规则集。它将为此检索用户选择的时区。
    5. 如果您有日历应用程序,所有这些规则都会失败。但在这种情况下,我认为 DateTime 本身可能是错误的工具。

    【讨论】:

    • 谢谢克里斯托弗。我的所有日​​期都存储为 UTC,交易日期除外。如果用户在日期选择器中选择了一个日期(没有时间,我只处理日期),我将其存储为所选日期。因为在澳大利亚,UTC+10,如果用户选择 22/Nov/2019,我就这样存储。但是服务器是 UTC,所以如果我选择“今天”的所有交易,我会得到昨天的交易。我需要知道用户的时区,这样我才能得到用户的“今天”。不是服务器。您的观点非常有效。我想我正在关注他们。
    • @Craig:交易日期是您在 UTC 中不应该拥有的最后一件事。 |没有时间的日期没有任何意义。同一时间点可以是 2 个,有时甚至是 3 个不同的日期 - 取决于您从哪个时区查看它。除非你有一个日历应用程序,否则你不应该尝试单独处理日期和时间。
    猜你喜欢
    • 1970-01-01
    • 2014-03-01
    • 2018-11-28
    • 2015-03-16
    • 1970-01-01
    • 1970-01-01
    • 2018-01-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多