web-dev-qa-db-ja.com

シーケンスにEFCF移行で複数の要素エラーが含まれています

いくつかのモデルを作成し、移行を追加してから、データベース更新操作を行いましたが、最後のデータベース更新操作では、次のエラーメッセージが表示されました。

シーケンスに複数の要素が含まれている

以下に私の移行構成を示します。

context.Categories.AddOrUpdate(p => p.CategoryName,
    new Category
    {
        CategoryName = "Sport"
    },
    new Category
    {
        CategoryName = "Music"
    }
);

context.Subcategories.AddOrUpdate(p => p.SubcategoryName,
    new Subcategory
    {
        SubcategoryName = "Football"
    },
    new Subcategory
    {
        SubcategoryName = "Basketball"
    },
    new Subcategory
    {
        SubcategoryName = "Piano"
    },
    new Subcategory
    {
        SubcategoryName = "Violin"
    }
);

context.Services.AddOrUpdate(p => p.ServiceType,
    new Service
    {
        ServiceType = "Football player",
        Category = { CategoryName = "Sport" },
        Subcategory = { SubcategoryName = "Football" }
    },
    new Service 
    {
        ServiceType = "Piano lessons",
        Category = { CategoryName = "Music" },
        Subcategory = { SubcategoryName = "Piano" }
    }
);

新しいサービスを追加すると問題が発生します。私はすでにカテゴリとサブカテゴリを持っています、そして私が好きならCategory = new Category { CategoryName = "Music" }その後は機能しますが、データベースでMusicエントリを2回取得します(この例の場合)。すでに追加されているカテゴリとサブカテゴリを使用したいと思います。以下にも私のモデルの定義があります。

public class Category
{
    [Key]
    public int CategoryID { get; set; }

    public string CategoryName { get; set; }
}

// Subcategory is defined the same way...

public class Service
{
    public int ServiceID { get; set; }

    public string ServiceType { get; set; }

    public virtual Category Category { get; set; }

    public virtual Subcategory Subcategory { get; set; }

}

それを解決する方法はありますか?

12
user1726549

シーケンスに複数の要素が含まれています

この例外は、p => p.CategoryNameなどの識別子式を指定してAddOrUpdateを使用しようとしたときに発生しました。 「Sport」または「Music」という同じ名前のCategoriesが2つある可能性があります。

これはSubcategoriesServicesでも発生する可能性があります。Subcategoriesp => p.SubcategoryNameを使用し、Servicesp => p.ServiceTypeを使用します。

最初にデータベースで重複するエントリをクリーンアップする必要があります。これは必須です。AddOrUpdateを使用する必要があるため、内部ではこのコードはSingleOrDefaultを使用し、複数の一致要素が見つかった場合は例外がスローされます。

オブジェクト参照がオブジェクトのインスタンスに設定されていません

このエラーは、おそらくこのコードが原因です。

Category = { CategoryName = "Sport" },
Subcategory = { SubcategoryName = "Football" }

新しいServiceを作成すると、デフォルトでnull Categoryが設定されます。CategoryNameを直接設定することはできません。

新しいサービスを追加すると問題が発生します。すでに追加されているカテゴリとサブカテゴリを使用したい。

CategoriesおよびSubcategoriesは、Serviceで使用できるように変数に格納する必要があります。

var sportCategory = new Category { CategoryName = "Sport" };
var musicCategory = new Category { CategoryName = "Music" };
context.Categories.AddOrUpdate(p => p.CategoryName, 
   sportCategory, musicCategory);

var footballSub = new Subcategory { SubcategoryName = "Football" };
var basketballSub = new Subcategory { SubcategoryName = "Basketball" };
var pianoSub = new Subcategory { SubcategoryName = "Piano" };
var violinSub = new Subcategory { SubcategoryName = "Violin" };
context.Subcategories.AddOrUpdate(p => p.SubcategoryName,
   footbalSub, basketballSub , pianoSub, violinSub);

context.Services.AddOrUpdate(p => p.ServiceType,
    new Service
    {
        ServiceType = "Football player",
        Category = sportCategory,
        Subcategory = footballSub
    },
    new Service 
    {
        ServiceType = "Piano lessons",
        Category = musicCategory,
        Subcategory = pianoSub
    }
);

しかし、上記のコードにはまだ問題があります。サービスが新しいエンティティである場合、既存のスポーツカテゴリと既存のサッカーサブカテゴリも追加されます。詳細については この記事 を参照してください。

ソリューション

既存のカテゴリと既存のサブカテゴリが追加されないようにするには、外部キー参照だけでなく、Serviceにも外部キー値を設定する必要があります。

[ForeignKey("Category")]
public int CategoryId { get; set; }
[ForeignKey("Subcategory")]
public int SubcategoryId { get; set; }

次に、移行を実行します。

Add-Migration AddServiceFKValues

そして、手動で 一時的な主キー を割り当て、サービスを定義するときにそれを使用します。この一時的な主キーは、既存のエンティティを扱う場合には必要ありませんが、新しいカテゴリまたはサブカテゴリが複数ある場合は、別の問題が発生する可能性があります。これを防ぐには、一時的な主キーを使用することをお勧めします。AddOrUpdateを呼び出した後、各エンティティの主キーが既存のエンティティである場合は更新されます。

var sportCategory = new Category { CategoryID = 1000, CategoryName = "Sport" };
var musicCategory = new Category { CategoryID = 1001, CategoryName = "Music" };
context.Categories.AddOrUpdate(p => p.CategoryName, 
   sportCategory, musicCategory);

var footballSub = new Subcategory { SubcategoryID = 1000, SubcategoryName = "Football" };
var basketballSub = new Subcategory { SubcategoryID = 1001, SubcategoryName = "Basketball" };
var pianoSub = new Subcategory { SubcategoryID = 1002, SubcategoryName = "Piano" };
var violinSub = new Subcategory { SubcategoryID = 1003, SubcategoryName = "Violin" };
context.Subcategories.AddOrUpdate(p => p.SubcategoryName,
   footbalSub, basketballSub , pianoSub, violinSub);

context.Services.AddOrUpdate(p => p.ServiceType,
    new Service
    {
        ServiceType = "Football player",
        CategoryID = sportCategory.CategoryID,
        SubcategoryID = footballSub.SubcategoryID
    },
    new Service 
    {
        ServiceType = "Piano lessons",
        CategoryID = musicCategory.CategoryID,
        SubcategoryID = pianoSub.SubcategoryID
    }
);

次に、データベースを更新します。

Update-Database
20
Yuliam Chandra