Entity Framework Core 自引用表 [英] Entity Framework Core self referencing table

查看:28
本文介绍了Entity Framework Core 自引用表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个名为 Item 的类,它引用下一个项目和上一个项目.

I have a class called Item which references the next item and the previous item.

public class Item
{
    private Item() { }

    public Item(string itemName)
    {
        ItemId = Guid.NewGuid();
        ItemName = itemName;
    }

    public Guid ItemId { get; set; }
    public string ItemName { get; set; }

    public Guid NextItemId { get; set; }
    public virtual Item NextItem { get; set; }

    public Guid PreviousItemId { get; set; }
    public virtual Item PreviousItem { get; set; }

    public Guid GroupId { get; set; }
    public virtual Group Group { get; set; }
}

我有另一个名为 Group 的表,用于对项目进行分组.

I have another table called Group it is for grouping it items.

public class Group
{
    private Group() { }
    public Group(string groupName)
    {
        GroupId = Guid.NewGuid();
        GroupName = groupName;
        GroupItems = new List<Item>();
    }

    public void AddGroupItem(Item item)
    {
        if (Items.Count == 0)
        {
            Items.Add(item);
        }
        else
        {
            item.PreviousItem = Items.Last();
            item.PreviousItemId = Items.Last().ItemId;
            Items.Last().NextItem = item;
            Items.Last().NextItemId = item.ItemId;

            Items.Add(item);
        }

    }

    public Guid GroupId { get; set; }
    public string GroupName { get; set; }
    public virtual IList<GroupItem> GroupItems { get; set; }
}

这是我创建和保存项目及其组的方法.

Here's how I create and save items and their group.

Group group1 = new Group("first group");
Item item1 = new Item("item 1");
Item item2 = new Item("item 2");
Item item3 = new Item("item 3");

group1.AddItem(item1);
group1.AddItem(item2);
group1.AddItem(item3);

_context.Add(group1);
_context.SaveChanges();

我如何编写 OnModelCreating 来处理对同一个表的两个引用.

How do I write the OnModelCreating to handle the two references to the same table.

推荐答案

您可以通过下一种方式来完成.首先,您应该为您的模型添加两个新属性 public virtual ListParentNextItems { 获取;放;}public virtual ListParentPreviousItems { 获取;放;}.所以你的模型将是这样的

You can do it in next way. First of all you should add two new properties to you model public virtual List<Item> ParentNextItems { get; set; } and public virtual List<Item> ParentPreviousItems { get; set; }. So your model will be something like this

public class Item
{
    private Item() { }

    public Item(string itemName)
    {
        ItemId = Guid.NewGuid();
        ItemName = itemName;
    }

    public Guid ItemId { get; set; }
    public string ItemName { get; set; }

    public Guid? NextItemId { get; set; }
    public virtual Item NextItem { get; set; }
    public virtual List<Item> ParentNextItems { get; set; }

    public Guid? PreviousItemId { get; set; }
    public virtual Item PreviousItem { get; set; }
    public virtual List<Item> ParentPreviousItems { get; set; }
}

然后你可以用下一种方式配置它

And than you can configure it in next way

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Item>()
        .HasKey(x => x.ItemId);
    modelBuilder.Entity<Item>()
        .HasOne(x => x.NextItem).WithMany(x => x.ParentNextItems).HasForeignKey(x => x.NextItemId)
        .Metadata.DeleteBehavior = DeleteBehavior.Restrict;
    modelBuilder.Entity<Item>()
        .HasOne(x => x.PreviousItem).WithMany(x => x.ParentPreviousItems).HasForeignKey(x => x.PreviousItemId)
        .Metadata.DeleteBehavior = DeleteBehavior.Restrict;


    base.OnModelCreating(modelBuilder);
}

仅此而已.但是,如果您想通过属性配置实现相同的效果,则可以跳过 void OnModelCreating(ModelBuilder modelBuilder) 更改并编写下一个模型:

That's all. But if you want to achieve the same with attribute configuration, than you can skip void OnModelCreating(ModelBuilder modelBuilder) changes and just write next model:

public class Item
{
    private Item() { }

    public Item(string itemName)
    {
        ItemId = Guid.NewGuid();
        ItemName = itemName;
    }

    [Key]
    public Guid ItemId { get; set; }
    public string ItemName { get; set; }

    public Guid? NextItemId { get; set; }

    [ForeignKey(nameof(NextItemId))]
    [InverseProperty(nameof(ParentNextItems))]
    public virtual Item NextItem { get; set; }

    [ForeignKey(nameof(NextItemId))]
    public virtual List<Item> ParentNextItems { get; set; }

    public Guid? PreviousItemId { get; set; }
    [ForeignKey(nameof(PreviousItemId))]
    [InverseProperty(nameof(ParentPreviousItems))]
    public virtual Item PreviousItem { get; set; }
    [ForeignKey(nameof(PreviousItemId))]
    public virtual List<Item> ParentPreviousItems { get; set; }
}

更新此外,您应该将 PreviousItemId、NextItemId 设为可选(Guid?),我在答案中做了相应的更改.

Update Also you should make PreviousItemId, NextItemId optional (Guid?), I did corresponding changes in my answer.

据我所知,您无法在一次 .SaveChanges() 行程中完成.创建第二个项目时,您应该已经将第一个项目保存到数据库中.(无论如何,这是另一个问题的主题)

And as far as I know, you just can't do it in one .SaveChanges() trip. When you create your second item you should already have first item saved into database. (anyway this is subject for another question)

但是无论如何,如果您将代码修改为类似的内容

But anyway if you modify you code to something like that

Group group1 = new Group("first group");
_context.Add(group1);
Item item1 = new Item("item 1");
group1.AddItem(item1);
_context.SaveChanges();
Item item2 = new Item("item 2");
group1.AddItem(item2);
_context.SaveChanges();
Item item3 = new Item("item 3");
group1.AddItem(item3);
_context.SaveChanges();

您可以在一次交易

这篇关于Entity Framework Core 自引用表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆