인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

Michael Lee님의 프로필 이미지
Michael Lee

작성한 질문수

[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part8: Entity Framework Core

EntityState.Unchanged로 처리 후 데이터베이스 조회시 다른 필드값이 null인 경우에 대한 질문

작성

·

260

0

안녕하세요?  Rookiss님.

몬스터가 드랍하는 아이템중에 stackable 아이템이 있어서 DB 조회없이 바로 갯수를 업데이트하고자 하여 아래와 같이 코드를 작성했습니다. 그 후에 다시 인벤토리 아이템을 클라에 통보하기 위하여 조회를 했으나 Stackable Item의 다른 Property가 모두 NULL이 되어 버리네요.  그래서 결국 아이템을 조회한 후에 갯수를 추가하니 정상적으로 처리가 되네요.

질문1 : 이런 경우 entityState를 사용하지 못하고 꼭 데이터베이스에 조회를 해야할 까요?

질문2 : stackable Item의 경우라면 어떤 로직으로 처리를 하는 게 바람직할 지 조언을 부탁드리고자 합니다.

------------------------------------------------------------------------------------

구글링을 통해 stackoverflow에서 찾아본 결과는 아래와 같습니다.

stackoverflow의 답변

https://stackoverflow.com/questions/28479933/after-setting-entitystate-unchanged-the-entity-properties-are-lost

=> 채택된 답변은 아이템의 갯수를 업데이트하기 전에 먼저 조회를 하라고 합니다.

------------------------------------------------------------------------------------

제가 작성중인 Dbtransaction 클래스의 메서드입니다.

------------------------------------------------------------------------------------

public static void RewardStackableItem(Player player, GameRoom room, int itemDbId, int totalCount)

{

if (player == null || room == null || itemDbId == 0)

return;

ItemDb oldItemDb = new ItemDb()

{

ItemDbId = itemDbId,

Count = totalCount

};

// YOU

Instance.Push(() =>

{

S_UpdateItem updateItemPacket = new S_UpdateItem();

using (AppDbContext db = new AppDbContext())

{

// 방법1.  EntityState 로 처리

//db.Entry(oldItemDb).State = EntityState.Unchanged;

//db.Entry(oldItemDb).Property(nameof(ItemDb.Count)).IsModified = true;

// 방법2 : 데이터베이스에 조회를 한 후에 처리

ItemDb item = db.Items

.Single(i => i.OwnerDbId == player.PlayerDbId && i.ItemDbId == itemDbId);

item.Count = totalCount;

bool success = db.SaveChangesEx();

if (success)

{

//문제가 발생하는 부분으로 인벤토리의 해당 아이템을 수정하지 않고 그냥 조회 후 인벤토리를 clear한 후에 다시 인벤토리의 아이템을 만들어서 클라에 통보하고자 하였습니다.

List<ItemDb> items = db.Items

.Where(i => i.OwnerDbId == player.PlayerDbId).ToList();

 

player.Inven.Items.Clear();

// Me

room.Push(() =>

{

                     foreach (ItemDb itemDb in items)

{

Item item = Item.MakeItem(itemDb);

if (item != null)

{

player.Inven.Add(item);

ItemInfo info = new ItemInfo();

info.MergeFrom(item.Info);

updateItemPacket.Items.Add(info);

}

}

player.Session.Send(updateItemPacket);

});

}

}

});

}

답변 2

1

Michael Lee님의 프로필 이미지
Michael Lee
질문자

답변 감사합니다.

현재 방치형 MMORPG를 만들기에 아이템 드랍이 너무 많아서 Rookiss님이 말씀해주신 부분에서 2번으로 갔습니다. Rookiss님이 강의하신 소스를 기반으로 인벤토리도 만들고 있거든요. 아침에 적용해보니 잘 되는군요.

마지막으로 unchanged가 호출되면 다른 필드의 값은 전부 DbContext상에서는 null 상태가 되고 그 후에 다른 클래스 어디에서 호출해도 결국 null이 되는 것이겠죠? => 요 부분도 테스트해봐야겠습니다. 

늘 루키스님에게 정말 감사하고 빨리 C++ Unreal Engine 부분도 강좌 나왔으면 합니다.

건강 유의하세요.

0

Rookiss님의 프로필 이미지
Rookiss
지식공유자

1)
ORM 특성상 조금 비효율적이라도
한번 Read(조회) 하고 다시 수정해서
Commit하는 방식이 가장 정석적이긴 합니다.

2)
1번이 정 마음에 안든다면, 서버 메모리에서도 Player의 Inventory 상태를
완전히 동일하게 메모리에서 들고 있고 (최초 접속 시 해당 플레이어의 모든 데이터를 db에서 로드)
disconnected 상태로 EF Core를 조작해 원하는 부분'만' 수정하고
데이터를 읽을 때 db에서 긁는게 아니라
서버 메모리상의 데이터를 클라에 보내주면 됩니다.

3)
그것도 아니라면 걍 SQL 쿼리를 직접 만들어서 보내 버려도 됩니다.

개발 속도에 중점을 둔다면 1번을,
그게 아니라 최대한 성능에 초점을 둔다면 2번을 선택할 것 같지만
사실 아주 큰 상관은 없고 현재 만드시는 게임 장르에 따라 또 달라질 수 있습니다.

Michael Lee님의 프로필 이미지
Michael Lee

작성한 질문수

질문하기