C# 在遗留数据中实现外键
我最近为我们公司重建了一个内部网站,我们必须从旧应用程序导入数据,该应用程序没有外键关系,更不用说约束了。以前,所有关系都是在代码端处理的 现在它已经使用.NETCore2.0和EntityFramework进行了重建,并具有强大的类型和关系,有很多遗留数据阻碍了我的EF迁移 例如,我们有一个C# 在遗留数据中实现外键,c#,sql,entity-framework,asp.net-core,C#,Sql,Entity Framework,Asp.net Core,我最近为我们公司重建了一个内部网站,我们必须从旧应用程序导入数据,该应用程序没有外键关系,更不用说约束了。以前,所有关系都是在代码端处理的 现在它已经使用.NETCore2.0和EntityFramework进行了重建,并具有强大的类型和关系,有很多遗留数据阻碍了我的EF迁移 例如,我们有一个companys表,其中一个“负责任的员工”基于该员工的LdapID。然而,旧的遗留数据也有2000多个条目,其中有人只输入了员工的姓名而不是ID。我没有权限清理这些数据,因此这不是一个选项 该站点已经构建
companys
表,其中一个“负责任的员工”基于该员工的LdapID
。然而,旧的遗留数据也有2000多个条目,其中有人只输入了员工的姓名而不是ID。我没有权限清理这些数据,因此这不是一个选项
该站点已经构建为在旧数据中显示这些“坏”值,但由于FK约束,我的所有迁移都失败了;例如,Employee ID
Smith,Bob
与Employee
表中的任何ID都不匹配。有没有一种方法可以在新数据上强制执行外键关系,同时允许旧的遗留数据继续使用“坏”值?现在,当我在添加新列后尝试运行迁移时,我得到的结果是:
ALTER TABLE语句与外键约束冲突
“FK_公司、员工、雇员ID”。数据库中发生冲突
“ets_web”,表“dbo.Employees”,列“LdapID”
临时的一次性修复对我不起作用。我需要能够在我们的测试和生产环境中创建可由自动化流程运行的迁移。我可以消除所有的限制,但我宁愿把它作为最后的手段
将属性设置为可空并不能解决此问题,因为它们已经是可空类型,而空不是问题所在。当外键Company.EmployeeID
在外键表Employee
中不存在时。其他表格中也存在类似问题
Company.cs
public class Company
{
#region Main Properties
public int ID { get; set; }
[Required, StringLength(100)]
[Display(Name = "Company Name")]
public string Name { get; set; }
[Required, StringLength(50)]
[Display(Name = "Address Line 1")]
public string AddressLine1 { get; set; }
[StringLength(50)]
[Display(Name = "Address Line 2")]
public string AddressLine2 { get; set; }
[StringLength(50)]
[Display(Name = "Address Line 3")]
public string AddressLine3 { get; set; }
[StringLength(50)]
[Display(Name = "City")]
public string City { get; set; }
[Display(Name = "State / Province")]
public string StateID { get; set; }
[DefaultValue("US")]
[Display(Name = "Country")]
public string CountryID { get; set; }
[Required, StringLength(7, ErrorMessage = "Zip / Postal Code must be 7 characters or less."), DataType(DataType.PostalCode)]
[Display(Name = "Zip / Postal Code")]
public string ZipCode { get; set; }
[StringLength(5)]
[Display(Name = "Zip Code Suffix")]
public string ZipSuffix { get; set; }
[StringLength(100)]
[Display(Name = "Contact Name")]
public string ContactName { get; set; }
[EmailAddress, StringLength(50)]
[Display(Name = "Contact Email")]
public string ContactEmail { get; set; }
[Display(Name = "Contact Phone"), DisplayFormat(DataFormatString = "{0:(###) ###-####}", ApplyFormatInEditMode = false)]
public long? ContactPhone { get; set; }
[Display(Name = "Contact Fax"), DisplayFormat(DataFormatString = "{0:(###) ###-####}", ApplyFormatInEditMode = false)]
public long? ContactFax { get; set; }
[StringLength(255)]
public string Comment { get; set; }
[Display(Name = "Responsible Employee")]
public string EmployeeID { get; set; }
/// <summary>
/// This property is used for concurrency, to prevent two users from submitting conflicting updates.
/// </summary>
[Timestamp]
public byte[] Timestamp { get; set; }
#endregion
#region Navigation Properties
public virtual State State { get; set; }
public virtual Country Country { get; set; }
// THIS is where the FK Relationship issue lies.
[ForeignKey("EmployeeID")]
public virtual Employee ResponsibleEmployee { get; set; }
#endregion
}
[Table("Employees")]
public class Employee
{
#region Main Properties
// This value is generated by our LDAP user system and input manually during Employee creation in the new system.
[Key, Required, StringLength(20), DatabaseGenerated(DatabaseGeneratedOption.None)]
[Display(Name = "LDAP / Global ID")]
public string LdapID { get; set; }
[Required, StringLength(50)]
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Required, StringLength(50)]
[Display(Name = "Last Name")]
public string LastName { get; set; }
[StringLength(35)]
public string Department { get; set; }
[StringLength(50), DataType(DataType.EmailAddress)]
public string Email { get; set; }
[Display(Name = "Work Phone"), DisplayFormat(DataFormatString = "{0:(###) ###-####}", ApplyFormatInEditMode = false)]
public long? WorkPhone { get; set; }
[Display(Name = "Mobile Phone"), DisplayFormat(DataFormatString = "{0:(###) ###-####}", ApplyFormatInEditMode = false)]
public long? MobilePhone { get; set; }
[StringLength(20)]
[Display(Name = "Fax Number")]
public string Fax { get; set; }
[StringLength(20)]
[Display(Name = "Mail Stop")]
public string MailStop { get; set; }
[DataType(DataType.DateTime)]
[Display(Name = "Last Login"), DisplayFormat(DataFormatString = "{0:d MMM yyyy h:mm tt} UTC", ApplyFormatInEditMode = true)]
public DateTime? LastLogin { get; set; }
/// <summary>
/// Used to modify security permissions for the user.
/// <para>Possible values are: 0 - Disabled, 1 - Read Only, 2 - Read/Write, 3 - Loan Admin, 4 - Super Admin</para>
/// </summary>
[Display(Name = "Access Level")]
public AccessType AccessLevel { get; set; }
/// <summary>
/// This property is used for concurrency, to prevent two users from submitting conflicting updates.
/// </summary>
[Timestamp]
public byte[] Timestamp { get; set; }
#endregion
#region Navigation Properties
[Display(Name = "Responsible Companies")]
public virtual ICollection<Company> ResponsibleCompanies { get; set; }
[InverseProperty("Employee")]
[Display(Name = "History")]
public virtual ICollection<History> History { get; set; }
#endregion
#region Unmapped Properties
/// <summary>
/// Returns the user's full name in the format: Lastname, Firstname
/// </summary>
[NotMapped]
[Display(Name = "Full Name")]
public string FullName => $"{LastName}, {FirstName}";
#endregion
}
上市公司
{
#区域主要属性
公共int ID{get;set;}
[所需长度(100)]
[显示(名称=“公司名称”)]
公共字符串名称{get;set;}
[所需长度(50)]
[显示(Name=“地址行1”)]
公共字符串AddressLine1{get;set;}
[长度(50)]
[显示(Name=“地址行2”)]
公共字符串AddressLine2{get;set;}
[长度(50)]
[显示(Name=“地址行3”)]
公共字符串AddressLine3{get;set;}
[长度(50)]
[显示(Name=“City”)]
公共字符串City{get;set;}
[显示(Name=“州/省”)]
公共字符串StateID{get;set;}
[违约价值(“美国”)]
[显示(Name=“Country”)]
公共字符串CountryID{get;set;}
[必需,StringLength(7,ErrorMessage=“邮政编码必须小于等于7个字符”)、数据类型(DataType.PostalCode)]
[显示(Name=“邮政编码”)]
公共字符串ZipCode{get;set;}
[第(5)款]
[显示(Name=“邮政编码后缀”)]
公共字符串ZipSuffix{get;set;}
[长度(100)]
[显示(Name=“联系人姓名”)]
公共字符串ContactName{get;set;}
[电子邮件地址,StringLength(50)]
[显示(Name=“联系电子邮件”)]
公共字符串ContactEmail{get;set;}
[Display(Name=“Contact Phone”)、DisplayFormat(DataFormatString=“{0:(#########-######]、ApplyFormatInEditMode=false]
公共长途电话{get;set;}
[Display(Name=“Contact Fax”)、DisplayFormat(DataFormatString=“{0:(########-######]、ApplyFormatInEditMode=false]
公共长联系人传真{get;set;}
[StringLength(255)]
公共字符串注释{get;set;}
[显示(Name=“责任员工”)]
公共字符串EmployeeID{get;set;}
///
///此属性用于并发,以防止两个用户提交冲突的更新。
///
[时间戳]
公共字节[]时间戳{get;set;}
#端区
#区域导航属性
公共虚拟状态状态{get;set;}
公共虚拟国家{get;set;}
//这就是FK关系问题所在。
[外籍钥匙(“员工ID”)]
公共虚拟员工责任员工{get;set;}
#端区
}
Employee.cs
public class Company
{
#region Main Properties
public int ID { get; set; }
[Required, StringLength(100)]
[Display(Name = "Company Name")]
public string Name { get; set; }
[Required, StringLength(50)]
[Display(Name = "Address Line 1")]
public string AddressLine1 { get; set; }
[StringLength(50)]
[Display(Name = "Address Line 2")]
public string AddressLine2 { get; set; }
[StringLength(50)]
[Display(Name = "Address Line 3")]
public string AddressLine3 { get; set; }
[StringLength(50)]
[Display(Name = "City")]
public string City { get; set; }
[Display(Name = "State / Province")]
public string StateID { get; set; }
[DefaultValue("US")]
[Display(Name = "Country")]
public string CountryID { get; set; }
[Required, StringLength(7, ErrorMessage = "Zip / Postal Code must be 7 characters or less."), DataType(DataType.PostalCode)]
[Display(Name = "Zip / Postal Code")]
public string ZipCode { get; set; }
[StringLength(5)]
[Display(Name = "Zip Code Suffix")]
public string ZipSuffix { get; set; }
[StringLength(100)]
[Display(Name = "Contact Name")]
public string ContactName { get; set; }
[EmailAddress, StringLength(50)]
[Display(Name = "Contact Email")]
public string ContactEmail { get; set; }
[Display(Name = "Contact Phone"), DisplayFormat(DataFormatString = "{0:(###) ###-####}", ApplyFormatInEditMode = false)]
public long? ContactPhone { get; set; }
[Display(Name = "Contact Fax"), DisplayFormat(DataFormatString = "{0:(###) ###-####}", ApplyFormatInEditMode = false)]
public long? ContactFax { get; set; }
[StringLength(255)]
public string Comment { get; set; }
[Display(Name = "Responsible Employee")]
public string EmployeeID { get; set; }
/// <summary>
/// This property is used for concurrency, to prevent two users from submitting conflicting updates.
/// </summary>
[Timestamp]
public byte[] Timestamp { get; set; }
#endregion
#region Navigation Properties
public virtual State State { get; set; }
public virtual Country Country { get; set; }
// THIS is where the FK Relationship issue lies.
[ForeignKey("EmployeeID")]
public virtual Employee ResponsibleEmployee { get; set; }
#endregion
}
[Table("Employees")]
public class Employee
{
#region Main Properties
// This value is generated by our LDAP user system and input manually during Employee creation in the new system.
[Key, Required, StringLength(20), DatabaseGenerated(DatabaseGeneratedOption.None)]
[Display(Name = "LDAP / Global ID")]
public string LdapID { get; set; }
[Required, StringLength(50)]
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Required, StringLength(50)]
[Display(Name = "Last Name")]
public string LastName { get; set; }
[StringLength(35)]
public string Department { get; set; }
[StringLength(50), DataType(DataType.EmailAddress)]
public string Email { get; set; }
[Display(Name = "Work Phone"), DisplayFormat(DataFormatString = "{0:(###) ###-####}", ApplyFormatInEditMode = false)]
public long? WorkPhone { get; set; }
[Display(Name = "Mobile Phone"), DisplayFormat(DataFormatString = "{0:(###) ###-####}", ApplyFormatInEditMode = false)]
public long? MobilePhone { get; set; }
[StringLength(20)]
[Display(Name = "Fax Number")]
public string Fax { get; set; }
[StringLength(20)]
[Display(Name = "Mail Stop")]
public string MailStop { get; set; }
[DataType(DataType.DateTime)]
[Display(Name = "Last Login"), DisplayFormat(DataFormatString = "{0:d MMM yyyy h:mm tt} UTC", ApplyFormatInEditMode = true)]
public DateTime? LastLogin { get; set; }
/// <summary>
/// Used to modify security permissions for the user.
/// <para>Possible values are: 0 - Disabled, 1 - Read Only, 2 - Read/Write, 3 - Loan Admin, 4 - Super Admin</para>
/// </summary>
[Display(Name = "Access Level")]
public AccessType AccessLevel { get; set; }
/// <summary>
/// This property is used for concurrency, to prevent two users from submitting conflicting updates.
/// </summary>
[Timestamp]
public byte[] Timestamp { get; set; }
#endregion
#region Navigation Properties
[Display(Name = "Responsible Companies")]
public virtual ICollection<Company> ResponsibleCompanies { get; set; }
[InverseProperty("Employee")]
[Display(Name = "History")]
public virtual ICollection<History> History { get; set; }
#endregion
#region Unmapped Properties
/// <summary>
/// Returns the user's full name in the format: Lastname, Firstname
/// </summary>
[NotMapped]
[Display(Name = "Full Name")]
public string FullName => $"{LastName}, {FirstName}";
#endregion
}
[表格(“员工”)]
公营雇员
{
#区域主要属性
//此值由LDAP用户系统生成,并在新系统中创建员工时手动输入。
[键,必需,StringLength(20),DatabaseGenerated(DatabaseGenerateOption.None)]
[显示(Name=“LDAP/Global ID”)]
公共字符串LdapID{get;set;}
[所需长度(50)]
[显示(Name=“First Name”)]
公共字符串名{get;set;}
[所需长度(50)]
[显示(Name=“Last Name”)]
公共字符串LastName{get;set;}
[第35段]
公共字符串部门{get;set;}
[StringLength(50),数据类型(DataType.EmailAddress)]
公共字符串电子邮件{get;set;}
[Display(Name=“Work Phone”)、DisplayFormat(DataFormatString=“{0:(#########-######]、ApplyFormatInEditMode=false]
公用长?工作电话{get;set;}
[Display(Name=“Mobile Phone”)、DisplayFormat(DataFormatString=“{0:(########-######]、ApplyFormatInEditMode=false]
公共长?移动电话{get;set;}
[行政长官(20)]
[显示(Name=“传真号码”)]
公共字符串传真{get;set;}
[行政长官(20)]
[显示(Name=“邮件停止”)]
公共字符串MailStop{get;set;}
[数据类型(数据类型.日期时间)]
[Display(Name=“Last Login”),DisplayFormat(DataFormatString=“{0:d MMM yyy h:mm tt}UTC”,ApplyFormatInEditMode=true)]
公共日期时间?LastLogin{get;set;}
///
///用于修改用户的安全权限。
///可能的值为:0-禁用、1-只读、2