【问题标题】:Entity Framework one-to-one relationship with one being optional throws error实体框架一对一关系,其中一个是可选的,会引发错误
【发布时间】:2013-10-30 16:51:30
【问题描述】:

我有一个产品类:

public class Product
{
    public int ID { get; set; }

    [Required]
    public string Name { get; set; }
    public decimal Price { get; set; }

    public Offer Offer { get; set; }
}

还有一个 Offer 类:

public class Offer
{
    public int ID { get; set; }

    [Required]
    public DateTime DateFrom { get; set; }
    public DateTime DateTo { get; set; }
    public decimal OfferPrice { get; set; }
    public Product Product { get; set; }
}

我想要实现的基本目标是在添加优惠时,产品与此优惠相关。因此,要约总是有产品,但产品并不总是需要要约。如果产品确实有优惠,我希望能够通过Product.Offer 访问它,但在此设置中,我在更新数据库时收到以下错误消息:

无法确定类型“WebshopISEC.Models.Offer”和“WebshopISEC.Models.Product”之间关联的主体端。此关联的主体端必须使用关系流式 API 或数据注释显式配置。

我尝试了很多东西(数据注释和 Fluent API)并无休止地搜索,但我似乎无法解决这个问题。我尝试过的 Fluent API 方法:

modelBuilder.Entity<Offer>()
            .HasRequired(x => x.Product)
            .WithOptional(x => x.Offer);

但这无济于事,我如何分配一个主要结束?上什么课?

【问题讨论】:

    标签: c# asp.net entity-framework asp.net-mvc-4 fluent-interface


    【解决方案1】:

    试试这个:

    public class Product
    {
        public int ID { get; set; }
    
        [Required]
        public string Name { get; set; }
        public decimal Price { get; set; }
    
        public Offer Offer { get; set; }
    }
    
    public class Offer
    {
        [ForeignKey("Product")]
        public int ID { get; set; }
    
        [Required]
        public DateTime DateFrom { get; set; }
        public DateTime DateTo { get; set; }
        public decimal OfferPrice { get; set; }
        public Product Product { get; set; }
    }
    

    【讨论】:

    • 感谢您的回复!这会引发以下错误:"Error: The new name 'ID' is already in use as a COLUMN name and would cause a duplicate that is not permitted."
    • 可以先删除数据库再更新数据库吗?
    • 我已经通过服务器资源管理器手动删除了所有表,现在我似乎无法恢复我的表。如何重置迁移历史并让它创建一个全新的基于数据库在我目前的课程上?
    • 删除迁移文件夹,然后用Enable-Migrtions重新开始
    • 经过大量的混乱和到处交换一些东西,重新创建迁移文件几次,它现在似乎可以正常工作了。感谢您的努力和时间!
    【解决方案2】:

    当您具有一对一关系时,一个实体必须是主体,另一个实体必须是从属。在这种情况下,我建议您通过像这样使用数据注释来确保 ProductId 在 Offer 中是 FK 和 PK:

        public class Product
        {
            public int ID { get; set; }
            [Required]
            public string Name { get; set; }
            public decimal Price { get; set; }
            public Offer Offer { get; set; }
        }
    
        public class Offer
        {
            public int ID { get; set; }
            [Required]
            public DateTime DateFrom { get; set; }
            public DateTime DateTo { get; set; }
            public decimal OfferPrice { get; set; }
            [Required]
            public Product Product { get; set; }
        }
    

    另一方面,您对自己的项目了解得更多,但我也建议您使用 1:N 关系。希望它成功了。

    【讨论】:

    • 嗨 Guillelon,感谢您的回复。我已尝试进行您的答案中描述的更改,但这导致了不同的错误:Error: The new name 'ID' is already in use as a COLUMN name and would cause a duplicate that is not permitted.
    • 如果您使用的是代码优先迁移,请从数据库中删除表,包括名为“__MigrationHistory”的表,并从您的项目中删除所有迁移。然后再次创建迁移并运行更新数据库。
    【解决方案3】:

    对于一对多关系,我收到了类似的错误消息。 我忘记在我的父属性上显式使用 ForeignKey 属性。 然后,当我尝试添加该属性时,我得到了一个无法运行的迁移。 我能够通过编辑迁移来解决该错误

    public override void Up()
    {
    
        //DropIndex("dbo.PurchaseManifestLines", new[] { "PurchaseOrderLineId" });
        //RenameColumn(table: "dbo.PurchaseManifestLines", name: "PurchaseOrderLineId", newName: "PurchaseOrderLine_Id1");
        //AddColumn("dbo.PurchaseManifestLines", "PurchaseOrderLine_Id", c => c.Int(nullable: false));
        //AlterColumn("dbo.PurchaseManifestLines", "PurchaseOrderLine_Id1", c => c.Int());
        //CreateIndex("dbo.PurchaseManifestLines", "PurchaseOrderLine_Id1");
        // gives error Column names in each table must be unique. Column name 'PurchaseOrderLine_Id' in table 'dbo.PurchaseManifestLines' is specified more than once.
    
    
        //replaced with 
        DropIndex("dbo.PurchaseManifestLines", new[] { "PurchaseOrderLineId" });
        DropColumn("dbo.PurchaseManifestLines", "PurchaseOrderLineId");
    
    }
    

    【讨论】:

    • 我也遇到过 Code-First 的情况,通过从代码中删除业务类,创建迁移以删除表并运行它,然后恢复业务对象代码并创建一个迁移以重新创建表。然后运行它。
    猜你喜欢
    • 2020-09-26
    • 1970-01-01
    • 1970-01-01
    • 2016-07-19
    • 1970-01-01
    • 1970-01-01
    • 2015-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多