我有两个表,来自遗留系统。这些表定期从两个独立的外部源更新,仅用作"只读"我的应用程序中的查找数据表:
DeliverySites
public partial class DeliverySite
{
public string CustomerID { get; set; } // PK
public string CustomerName { get; set; }
public string DeliveryAddress { get; set; }
public string BillingAddress { get; set; }
//... fields removed for clarity.
// Navigational Properties.
public virtual ICollection<Item> Items { get; set; }
}
public class DeliverySiteMap : EntityTypeConfiguration<DeliverySite>
{
public DeliverySiteMap()
{
// Primary Key
this.HasKey(t => t.CustomerID);
// Properties
this.Property(t => t.CustomerID)
.IsRequired()
.HasMaxLength(50);
this.Property(t => t.CustomerName)
.IsRequired()
.HasMaxLength(50);
this.Property(t => t.DeliveryAddress)
.IsRequired();
this.Property(t => t.BillingAddress)
.IsRequired();
// Table & Column Mappings
this.ToTable("DeliverySites");
this.Property(t => t.CustomerID).HasColumnName("CustomerID");
this.Property(t => t.CustomerName).HasColumnName("CustomerName");
this.Property(t => t.DeliveryAddress).HasColumnName("DeliveryAddress");
this.Property(t => t.BillingAddress).HasColumnName("BillingAddress");
}
}
项
public partial class Item
{
public string Item { get; set; } // PK
public string ItemDescription { get; set; }
public decimal Brand { get; set; }
public decimal Price { get; set; }
public string CustomerID { get; set; } // PK + FK
//... fields removed for clarity.
// Navigational Properties.
public virtual DeliverySite DeliverySite { get; set; }
}
public class ItemMap : EntityTypeConfiguration<Item>
{
public ItemMap()
{
// Primary Key
this.HasKey(t => new { t.Item, t.CustomerID });
// Properties
this.Property(t => t.UserItem)
.HasMaxLength(50);
this.Property(t => t.UserItemDescription)
.HasMaxLength(255);
this.Property(t => t.CCItem)
.IsRequired()
.HasMaxLength(50);
this.Property(t => t.CCItemDescription)
.IsRequired()
.HasMaxLength(255);
this.Property(t => t.CustomerID)
.HasMaxLength(50);
// Table & Column Mappings
this.ToTable("Items");
this.Property(t => t.Item).HasColumnName("Item");
this.Property(t => t.ItemDescription).HasColumnName("ItemDescription");
this.Property(t => t.Brand).HasColumnName("Brand");
this.Property(t => t.Price).HasColumnName("Price");
this.Property(t => t.CustomerID).HasColumnName("CustomerID");
}
}
鉴于这些表是独立更新的,可能会有&#34; Items&#34;输入&#34; DeliverySites&#34;哪个不存在。
因此,我想建立一个可选的关系。 (所以我可以在我的应用程序中使用导航属性,但这样我就不会阻止这些表被独立更新。)
在我的ItemMap : EntityTypeConfiguration<Item>
内,我尝试了以下内容:
this.HasOptional(x => x.DeliverySite)
.WithMany(x => x.Items)
.HasForeignKey(x => x.CustomerID)
.WillCascadeOnDelete(false);
但是我收到了这个错误:
System.Data.Entity.Edm.EdmAssociationType ::多重冲突 使用Role&#39; Item_DeliverySite_Target&#39;中的引用约束在 关系&#39; Item_DeliverySite&#39;。因为所有的属性 依赖角色是不可为空的,主要角色的多样性 必须是&#39; 1&#39;。
我应该如何实施这种关系?
此外,如果我可以在数据库中不添加任何FK约束的情况下执行此操作,那将是理想的。这可能吗?
答案 0 :(得分:1)
您很可能遇到此错误,因为需要Item.CustomerID
。虽然您没有在映射中调用IsRequired()
,但它是必需的,因为它是复合主键的一部分......
this.HasKey(t => new { t.Item, t.CustomerID });
...并且因为复合键的每一列都不允许数据库中有NULL
。因此EF希望有映射
this.HasRequired(x => x.DeliverySite)
.WithMany(x => x.Items)
.HasForeignKey(x => x.CustomerID)
.WillCascadeOnDelete(false);
对我而言,真正的问题似乎是您正在尝试使用EF创建关系和导航属性,而数据库中没有真正的关系和外键约束。
如果Item.CustomerID
在数据库中的值不是表DeliverySites
中的行,则不能使用HasRequired
,因为如果您尝试加载Item
1 {} Include
EF DeliverySite
会创建INNER JOIN
和Items
,而DeliverySite
和CustomerID
不会通过{{1}引用现有LEFT OUTER JOIN
根本不会被加载。所以,基本上你会得到错误的查询结果。另一方面,您不能使用可选映射(这将导致CustomerID
),因为DeliverySite
是PK的一部分,它会导致您的异常。
老实说,使用遗留数据库模式我不会尝试在EF模型中引入导航属性和人为关系。如果您在一个查询中需要“相关”Item
和CustomerID
,我可能更愿意使用手动LINQ连接和DeliverySite
作为普通标量属性来连接数据和将加载的Item
和{{1}}投影到专门的类(或匿名对象)中。
答案 1 :(得分:0)
我相信如果您删除外键并且只是创建它,这将有效:
this.HasOptional(x => x.DeliverySite)
.WithMany(x => x.Items);
答案 2 :(得分:0)
我知道这不是您想要的答案,但恕我直言,您可以更好地花时间制作确保旧数据库完整性的解决方案。在ORM中寻找非规范化数据库中的解决方法不仅是不好的做法,而且会给同行带来麻烦并使您的产品贬值。不确定数据是如何保留的,但您可以将项目保存在临时表中,并且仅在相应的交付站点存在时才添加到规范化表中。