EntityFrameworkでPostgreSQLのデータを取得するとバグる

以下のteratailで質問されている内容が私の環境でも発生した。

https://teratail.com/questions/88507

不具合は質問内容と同様、ある特定のテーブルのデータを取得したときレコードが重複されて取得されてしまうことがあるというもの。

teratailではOS再起動で直ったとあるが私の環境では直らなかった。

さっさと結論だけ読みたい場合は**[こちら](#結論)**

# バージョン情報
.NET 5.0
Microsoft.EntityFrameworkCore v5.0.12
Npgsql.EntityFrameworkCore.PostgreSQL v5.0.10


# 現象

以下のPersonTableを取得する場合を例にする。

``` PersonTable.cs
using System;
using SystemComponentModel.DataAnnotations.Schemes;

namespace SampleProject
{
    [Table("persontbl")]
    [Serializable]
    public class PersonTable
    {
        [Column("id")]
        public string ID{ get; set; }
        [Column("name")]
        public string Name{ get; set; }
        [Column("age")]
        public decimal Age{ get; set; }
    }
```

DBには以下の値が入っているものとする。

|id  |name|age|
|----|----|----|
{0001|taro|21|
|0002|shigeru|12|
|0003|satoshi|8|
|0004|hikaru|14|
|0005|shigezo|87|
|0006|takeshi|10|

そして、以下のコードでDBのレコードを取得する。

``` DBAccess_BEFORE.cs
using System;
using System.Collections.Generic;

namespace SampleProject
{
    public class DBAccess
    {
        public DatabaseAccess(DatabaseContext context)
        {
            this.context = context;
        }

        public List<PersonTable> GetShota()
        {
            int[] targetAges = new[]{ 6, 7, 8, 9, 10, 11, 12 };
            var results = context.PersonTable
                .Where(x => (targetAges.Contains(x.Age) == true))
                .ToList();

            return results;
        }
    }
}
```

GetShotaメソッドの取得結果として期待されるのはこのようになる。

|id  |name|age|
|----|----|----|
|0002|shigeru|12|
|0003|satoshi|8|
|0006|takeshi|10|

しかし、不具合発生時にはこのようになってしまう。

|id  |name|age|
|----|----|----|
|0002|shigeru|12|
|0003|satoshi|8|
|0003|satoshi|8|

あるいはこう。

|id  |name|age|
|----|----|----|
|0002|shigeru|12|
|0002|shigeru|12|
|0002|shigeru|12|

# 原因

不明。
別のテーブルだと起きない。

# 解決策

EntityFramewok + LINQ で取得する方法としての解決策は

**ありません。**

（情報お待ちしております。）

# 結論

どうにもならないのでSQLを直打ちすることにした。

``` DBAccess_AFTER.cs
using System;
using System.Collections.Generic;

namespace SampleProject
{
    public class DBAccess
    {
        public DatabaseAccess(DatabaseContext context)
        {
            this.context = context;
        }

        public List<PersonTable> GetShota()
        {
            int[] targetAges = new[]{ 6, 7, 8, 9, 10, 11, 12 };
            List<PersonTable> results = new();
            using (var command = context.Database.GetDbConnection().CreateCommand())
            {
                string inCondition = "";
                for (int i = 0; i < targetAges.Count; i++)
                {
                    inCondition += $"{targetAges[i]}";
                    if (i != targetAges.Count - 1)
                    {
                        inCondition += ",";
                    }
                }

                if (command.Connection.State != ConnectionState.Open)
                {
                    command.Connection.Open();
                }

                command.CommandText = $"SELECT * FROM persontbl WHERE age IN ({inCondition});";
                using (var dbReader = command.ExecuteReader())
                {
                    bool read = dbReader.Read();
                    while (read)
                    {
                        string id = dbReader["id"] as string;
                        string name = dbReader["name"] as string;
                        decimal age = (decimal)dbReader["age"];

                        results.Add(new(){ ID = id, Age = (int)age, Name = name });

                        read = dbReader.Read();
                    }
                }

                command.Connection.Close();
            }

            return results;
        }
    }
}
```

不本意ながらまあ一番確実だよね・・・。

# 留意事項


**私はショタコンではない。**

DBAccess_AFTER.csはベタで処理を書いているけど、もちろんラッパーとか作ってちゃんと構造化してね？

同コードは「とりあえず動いた！」という段階で投稿したものなので、部分的に間違っている可能性がある。

あと、エラー処理もしていない。

# 勝手に質疑応答

#####Q：なんで x.Age >= 6 || x.Age <= 12 の条件でLINQ作ってないの？
A：元のソースだとその部分が string型だったんよ。
そのまま掲載できないから改変してたらdecimalになってた。すまん。

#####Q：ほかに試したことは？
A：ContainsメソッドでSQLのIN句に相当する条件を作っているのがいけないのかと思って、Whereの条件取っ払って全件取得にしても駄目だった。
どうやっても重複するレコードが発生してしまった。