简体   繁体   中英

Entity Framework: removing a relationship is not working

In my multiplayer game the player has many items in their inventory. Some of which are block items. Block items in the player's inventory can also be assigned to "slots" (for a quick slot system in the game).

The way I have the entity classes is as follows: I have an entity of type PlayerContext that has an Inventory entity. The Inventory entity extends the ItemContainer entity which has many ItemContext entities. The BlockItem entity extends the ItemContext entity. The PlayerContext also has "slots" that are a foreign key reference to BlockItem entities.

I encounter a problem when I am changing the "slots". I can assign a BlockItem to a slot and that is saved in the database. However I can't remove a BlockItem from a slot. I am trying to do this by setting the slot = null and then updating the PlayerContext . The newly assigned BlockItem is saved as a foreign key but the slot that I am trying to clear is not saved and still has the reference to the BlockItem .

In code this looks like:

class ChunkContext : DbContext
{
    ...
    public DbSet<PlayerContext> Players { get; set; }
    public DbSet<ItemContext> Items { get; set; }
    public DbSet<BlockItem> blockItems { get; set; }
    public DbSet<ItemContainerContext> ItemContainers { get; set; }
    public DbSet<Inventory> Inventories { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseSqlite("Data Source=../chunks.db");

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        ...
        modelBuilder.Entity<PlayerContext>().HasOne(p => p.inventory);
        modelBuilder.Entity<ItemContext>().HasKey(i => i.id);
        modelBuilder.Entity<ItemContext>().HasOne(i => i.container).WithMany(ic => ic.items);
        ...
        modelBuilder.Entity<ItemContainerContext>().HasKey(ic => ic.id);
        modelBuilder.Entity<ItemContainerContext>().HasMany(ic => ic.items).WithOne(item => item.container);
        base.OnModelCreating(modelBuilder);
    }

    ...
}

[Index(nameof(username), IsUnique = true)]
public class PlayerContext
{
    public PlayerContext() { }

    [Key]
    public int id { get; set; }
    ...

    [Required]
    public Inventory inventory { get; set; }

    // resource slots. this is digusting and I'm sorry
    public BlockItem slot0 { get; set; }
    public BlockItem slot1 { get; set; }
    public BlockItem slot2 { get; set; }
    public BlockItem slot3 { get; set; }
    public BlockItem slot4 { get; set; }
    public BlockItem slot5 { get; set; }
    public BlockItem slot6 { get; set; }
    public BlockItem slot7 { get; set; }

    internal void SetResourceSelectorSlot(int slotIndex, int itemId)
    {
        using (var db = new ChunkContext())
        {
            if (slotIndex == 0) slot0 = inventory.FindItem(itemId) as BlockItem;
            else if (slot0 != null && slot0.id == itemId) slot0 = null;

            if (slotIndex == 1) slot1 = inventory.FindItem(itemId) as BlockItem;
            else if (slot1 != null && slot1.id == itemId) slot1 = null;

            if (slotIndex == 2) slot2 = inventory.FindItem(itemId) as BlockItem;
            else if (slot2 != null && slot2.id == itemId) slot2 = null;

            if (slotIndex == 3) slot3 = inventory.FindItem(itemId) as BlockItem;
            else if (slot3 != null && slot3.id == itemId) slot3 = null;

            if (slotIndex == 4) slot4 = inventory.FindItem(itemId) as BlockItem;
            else if (slot4 != null && slot4.id == itemId) slot4 = null;

            if (slotIndex == 5) slot5 = inventory.FindItem(itemId) as BlockItem;
            else if (slot5 != null && slot5.id == itemId) slot5 = null;

            if (slotIndex == 6) slot6 = inventory.FindItem(itemId) as BlockItem;
            else if (slot6 != null && slot6.id == itemId) slot6 = null;

            if (slotIndex == 7) slot7 = inventory.FindItem(itemId) as BlockItem;
            else if (slot7 != null && slot7.id == itemId) slot7 = null;

            db.Players.Update(this);
            db.SaveChanges();
        }

    }
}

public class ItemContext
{
    [Key]
    public int id { get; set; }
    public ItemContainerContext container { get; set; }
    ...
}

public class BlockItem : ItemContext
{
    ...
}

The SetResourceSelectorSlot is successfully setting and saving the foreign key reference to the items. But it is not clearing the field when I set it to null. When I set it to null it's not changed in the database at all. I don't want to delete the BlockItem that it references (because it's still in the player's inventory). I just want the field to be set to NULL in the database. The field is nullable and it's null by default. But nothing I do can change it back to being null after it has been set. Also I am setting the field to be null and can confirm that when debugging. But that change is not propagated to the DB.

Adding this line:

db.Entry(this).Reference(p => p.slot0).IsModified = true;

after I set the field to null makes sure it is saved in the database.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM