实体框架,多个可选,没有外键?

时间:2013-06-11 11:59:34

标签: c# entity-framework-5

我有两个表,来自遗留系统。这些表定期从两个独立的外部源更新,仅用作"只读"我的应用程序中的查找数据表:

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约束的情况下执行此操作,那将是理想的。这可能吗?

3 个答案:

答案 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 JOINItems,而DeliverySiteCustomerID不会通过{{1}引用现有LEFT OUTER JOIN根本不会被加载。所以,基本上你会得到错误的查询结果。另一方面,您不能使用可选映射(这将导致CustomerID),因为DeliverySite是PK的一部分,它会导致您的异常。

老实说,使用遗留数据库模式我不会尝试在EF模型中引入导航属性和人为关系。如果您在一个查询中需要“相关”ItemCustomerID,我可能更愿意使用手动LINQ连接和DeliverySite作为普通标量属性来连接数据和将加载的Item和{{1}}投影到专门的类(或匿名对象)中。

答案 1 :(得分:0)

我相信如果您删除外键并且只是创建它,这将有效:

this.HasOptional(x => x.DeliverySite)
    .WithMany(x => x.Items);

答案 2 :(得分:0)

我知道这不是您想要的答案,但恕我直言,您可以更好地花时间制作确保旧数据库完整性的解决方案。在ORM中寻找非规范化数据库中的解决方法不仅是不好的做法,而且会给同行带来麻烦并使您的产品贬值。不确定数据是如何保留的,但您可以将项目保存在临时表中,并且仅在相应的交付站点存在时才添加到规范化表中。

相关问题