いくつかのモデルを作成し、移行を追加してから、データベース更新操作を行いましたが、最後のデータベース更新操作では、次のエラーメッセージが表示されました。
シーケンスに複数の要素が含まれている
以下に私の移行構成を示します。
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; }
}
それを解決する方法はありますか?
シーケンスに複数の要素が含まれています
この例外は、p => p.CategoryName
などの識別子式を指定してAddOrUpdate
を使用しようとしたときに発生しました。 「Sport」または「Music」という同じ名前のCategories
が2つある可能性があります。
これはSubcategories
とServices
でも発生する可能性があります。Subcategories
はp => p.SubcategoryName
を使用し、Services
はp => 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