2

最初に EF コードを使用して、多対多の関係を持つデータベースを作成しようとしています。

public class Item
{
    public int ItemId { get; set; }
    public String Description { get; set; }
    public ICollection<Tag> Tags { get; set; }

    public Item()
    {
        Tags = new HashSet<Tag>();
    }
}

public class Tag
{
    public int TagId { get; set; }
    public String Text { get; set; }
    public ICollection<Item> Presentations { get; set; }

    public Tag()
    {
        Presentations = new HashSet<Item>();
    }
}

public class ItemsEntities : DbContext
{
    public DbSet<Item> Items { get; set; }
    public DbSet<Tag> Tags { get; set; }
}

その後、データベースにアイテムを追加しています

var tag = new Tag { Text = "tag1" };
var item = new Item
{
    Description = "description1",
    Tags = new List<Tag>()
};
item.Tags.Add(tag);
using (var db = new ItemsEntities())
{
    db.Items.Add(item);
    db.SaveChanges();
}

問題は、関連付けられたタグを持つアイテムを出力できないことです。コントローラーは次のようになります。

public ActionResult Index()
{
    ItemsEntities db = new ItemsEntities();
    return View(db.Items.ToList());
}

ビューページには次のコードがあります。

@foreach (var item in Model) 
{
   <tr>
    <td>
        @Html.DisplayFor(model => item.Description)
    </td>
    <td>
        @foreach (var tag in item.Tags)
        {
            @tag.Text
        }
    </td>
</tr>
}

テーブルには「description1」と「tag1」が含まれているはずですが、「description1」しか得られません。どこに問題があるのか​​ 本当にわかりません。これを行う正しい方法は何ですか?

4

2 に答える 2

2

ナビゲーション プロパティをマークする必要がありますvirtual

public class Item
{
    public int ItemId { get; set; }
    public String Description { get; set; }
    public virtual ICollection<Tag> Tags { get; set; }

    public Item()
    {
        Tags = new HashSet<Tag>();
    }
}

public class Tag
{
    public int TagId { get; set; }
    public String Text { get; set; }
    public virtual ICollection<Item> Presentations { get; set; }

    public Tag()
    {
        Presentations = new HashSet<Item>();
    }
}
于 2012-07-05T03:33:26.680 に答える
1

virtualコードを機能させるには、コレクションのプロパティを@danludwig の指示どおりにマークすることができます。コレクションのプロパティをvirtualEF Code First としてマークすると、ビュー内の項目を反復処理するときに、これらのプロパティが遅延読み込みされます。このアプローチを使用すると、SELECT N+1 問題が発生します。ビュー コードを調べてみましょう。

@foreach (var item in Model) 
{
   <tr>
     <td>
       @Html.DisplayFor(model => item.Description)
     </td>
     <td>
       @foreach (var tag in item.Tags)
       {
         @tag.Text
       }
     </td>
   </tr>
}

このforeachループでは、EF データ コンテキストを使用して選択されたモデル内のすべてのアイテムを反復処理します。

db.Items.ToList()

これが最初の選択です。Tagsしかし、上記のビューでは、アイテムのプロパティにアクセスするたびに別の選択が実行されます。重要なことは、すべてのアイテムに対してです。つまり、 に 100 個ある場合Itemsdb.Items DbSet101 個の選択を実行することになります。これは、ほとんどのシステムでは受け入れられません。

より良いアプローチは、各アイテムのタグを事前に選択することです。1 つのアプローチは Include、アイテムに関連するタグを使用または選択して専用オブジェクトにすることです。

public class ItemWithTags 
{
    public Item Item { get;set; }
    public IEnumerable<Tag> Tags { get;set; }
}

public ActionResult Index()
{
    ItemsEntities db = new ItemsEntities();

    var itemsWithTags = db.Items.Select(item => new ItemWithTags() { Item = item, Tags = item.Tags});
    return View(itemsWithTags.ToList());
}

ビューでは、コレクションを反復処理し、itemsWithTagsアイテムのプロパティにアクセスし、タグの場合は のTagsプロパティにアクセスできますItemWithTags

コードのもう 1 つの問題は、ItemsEntities DbContextがコードで開かれているが閉じられていないことです。VS MVC テンプレートを使用してDbContext、開閉を正しく処理するコントローラーを生成できます。

MVC Mini Profiler などのツールを使用して、データベースに対して実行されたコマンドを検査できます。このStackoverflow Questionは、EF Code First を使用して MVC Mini Profiler をセットアップする方法を示しています。

于 2012-07-05T04:00:38.687 に答える