两个自我引用的一对多关系

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了两个自我引用的一对多关系相关的知识,希望对你有一定的参考价值。

这是我的第一个问题,所以如果有格式问题或配方不清楚,请不要犹豫告诉我。

我有一个名为Item的实体,除了其他属性之外,还有两个链接到同一个DBSet中的其他项(“GlobalItem”和“DepositItem”)。

public class Item
{
    public int ItemID { get; private set; }

    public virtual Item GlobalItem { get; set; }

    public virtual Item DepositItem { get; set; }

    protected Item() { }
}

映射完成如下:

 public ItemMap()
    {
        HasKey(o => o.ItemID);

        ToTable("Item", "dbo");

        // Relationships
        HasOptional(o => o.GlobalItem)
            .WithMany()
            .Map(m => m.MapKey("GlobalItemID"));

        HasOptional(o => o.DepositItem)
            .WithMany()
            .Map(m => m.MapKey("DepositItemID"));
    }

构建过程是成功的,但是当我尝试Get All()时,抛出以下异常:

System.Data.Entity.Core.EntityCommandExecutionException:'执行命令定义时发生错误。有关详细信息,请参阅内部异常。

内在例外:

SqlException:无效的列名称“DepositItem_ItemID”。

列名称“DepositItem_ItemID”无效。

列名称“DepositItem_ItemID”无效。

我知道这个异常通常是由简单的映射错误引起的,但是在这种情况下,我确实卡住了,因为我确保ColumnName和MapKey是正确的,并且所有常用的解决方法就像在实体中显式定义DepositItemID并使用.HasForeignKey(k = k.DepositItemID)而不是以前的映射定义没有改变任何东西。

EF6是否存在多个自引用虚拟属性的一般问题?有人可以解释一下,为什么映射键被DepositItem忽略,但GlobalItem却没有忽略?有人能在我的设计中找到一个缺陷吗?

致以最诚挚的问候,感谢您的努力,

答案

这个模型没什么问题。也许您的数据库需要重新创建。

看到:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Linq;

namespace Ef6Test
{
    public class Item
    {
        public int ItemID { get; private set; }

        //public virtual Category Category { get; set; }

        public string Description { get; set; }

        public string ItemLookupCode { get; private set; }

        public virtual Item GlobalItem { get; set; }

        public virtual Item DepositItem { get; set; }

        public bool IsDeleted { get; set; }

        //public virtual ItemExtension ItemExtension { get; set; }



        public Item() { }
    }
    class Db : DbContext
    {

       public DbSet<Item> Items { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<Item>().HasKey(o => o.ItemID);

            modelBuilder.Entity<Item>().ToTable("Item", "dbo");

            // Relationships
            //HasRequired(t => t.Category)
            //    .WithMany(o => o.Items)
            //    .Map(m => m.MapKey("CategoryID"));

            modelBuilder.Entity<Item>().HasOptional(o => o.GlobalItem)
                .WithMany()
                .Map(m => m.MapKey("GlobalItemID"));

            modelBuilder.Entity<Item>().HasOptional(o => o.DepositItem)
                .WithMany()
                .Map(m => m.MapKey("DepositItemID"));

            //HasOptional(o => o.ItemExtension)
            //    .WithRequired(o => o.Item);



        }



        class Program
        {


            static void Main(string[] args)
            {

                Database.SetInitializer(new DropCreateDatabaseAlways<Db>());


                using (var db = new Db())
                {
                    db.Database.Log = m => Console.WriteLine(m);
                    db.Database.Initialize(true);

                    var items = db.Items.ToList();


                }


                Console.WriteLine("Hit any key to exit");
                Console.ReadKey();
            }
        }
    }
}

创建

CREATE TABLE [dbo].[Item] (
    [ItemID] [int] NOT NULL IDENTITY,
    [Description] [nvarchar](max),
    [ItemLookupCode] [nvarchar](max),
    [IsDeleted] [bit] NOT NULL,
    [DepositItemID] [int],
    [GlobalItemID] [int],
    CONSTRAINT [PK_dbo.Item] PRIMARY KEY ([ItemID])
)
另一答案

我建议你的对象应该是

public class Item
{
    public int ItemID { get; private set; }

    public int? GlobalItemID { get; set; }

    public int? DepositItemID { get; set; }

    [ForeignKey("GlobalItemID")]
    public Item GlobalItem { get; set; }

    [ForeignKey("DepositItemID")]
    public Item DepositItem { get; set; }

    protected Item() { }
}
另一答案

Item模型和映射都很好。

该问题是由另一个未映射到数据库中的实体中的旧导航属性(也称为“DepositItem”)引起的。

以上是关于两个自我引用的一对多关系的主要内容,如果未能解决你的问题,请参考以下文章

一对多和递归关系 - 强制设置值

一对多、自引用关系 Symfony

Code First - 自引用一对多关系

同一实体类型代码的多个一对多关系优先

Swift如何实现通用类型的弱引用数组(下)

为自引用表设置一对多关系