23

MVC.NET Web API、DB を最初に使用した EF を使用しており、コンテキストで遅延読み込みをオフにしています。LazyLoading がオフになっていても、EF はあまりにも多くのデータを返しています。

たとえば、1 つのロールを持つユーザーがいます。ユーザーをクエリしてロールを含めると、ユーザーがコンテキストに読み込まれているため、Role.Users プロパティにデータが自動的に入力されます。

私が要求したものだけを EF に提供してもらえないのはなぜですか? それとも、ここで何か大きなものを見逃していますか?

public partial class User
{
    public int UserID { get; set; }
    public string Title { get; set; }
    public string Email { get; set; }
    public int RoleID { get; set; }

    ....

    public virtual Role Role { get; set; }
} 

public partial class Role
{
    public int RoleID { get; set; }
    public string RoleName { get; set; }

    ....

    public virtual ICollection<User> Users { get; set; }
} 




return db.Users.Include(u => u.Role);
// ^^ user.Role.Users is filled with 1000s of users

TL;DR - 直接 .Include() しない限り、EF がデータをナビゲーション プロパティ/コレクションに読み込まないようにしたい。JSON にシリアル化するときは、明示的に要求するものだけが必要です。遅延ロード オフを使用しても、既にコンテキスト内にあるナビゲーション プロパティ (つまり、通常は「循環参照」) がロードされて返されるようです。

4

5 に答える 5

22

表示されている動作はRelationship Fixupと呼ばれ、無効にすることはできません。

ユーザーにロールをロードしてシリアライズし、どこかに送信する場合、エンティティがロードされたコンテキストでエンティティの変更を追跡したくないと思います。したがって、それらをコンテキストにアタッチする必要はありません。あなたが使用することができます:

return db.Users.Include(u => u.Role).AsNoTracking();

または、@STLRick で提案されているように、シリアル化に特化したオブジェクトへの射影を使用します。

于 2012-12-03T22:15:15.287 に答える
2

を使用して、必要なものだけを選択できますSelect()

var users = _db.Users.Select(x => new
{
    UserID = x.UserID,
    Title = x.Title,
    Email = x.Email,
    RoleID = x.RoleID
}).AsEnumerable();
于 2012-12-03T22:15:06.413 に答える
2

遅延読み込みをオンにすると、ナビゲーション プロパティが返されるのは正しいことです。これは、それらが読み込まれる原因となるシリアライザーによって「処理」されるためです。プロパティを null として返す場合は、遅延読み込みをオフにする必要があります。つまり、エンティティがコンテキストに読み込まれると (たとえば、他のクエリを介して)、それらはシリアライザーによって処理されるように見えます。したがって、答えは、ナビゲーション プロパティを返さないようにシリアライザーに指示することです。これを行うために私が見つけた最善の方法は、DTO (データ転送オブジェクト) を使用することです。これにより、実際のエンティティではなく、必要なデータを正確に返すことができます。

DTO は次のようになります。

public partial class UserDto
{
    public UserDto(user User)
    {
        UserID = user.UserID;
        Title = user.Title;
        //... and so on
    }
    public int UserID { get; set; }
    public string Title { get; set; }
    public string Email { get; set; }
    public int RoleID { get; set; }

    //exclude the Role navigation property from your DTO
}

...そして、次のようなことができます:

return db.Users.Include(u => u.Role).Select(user => new UserDto(user));
于 2013-01-24T18:18:47.717 に答える
1

含めるように指示したもの以外は何もロードしたくありません。

Explicit Loadingを使用する必要があるようです。基本的に、次のように特定のエンティティをロードできます。

context.Include("Roles")

私の知る限り、関連エンティティを含めるべきではありません。遅延読み込みは実際に無効にする必要があり、ナビゲーション プロパティを明示的に読み込むことができますLoad

于 2012-12-03T22:00:12.350 に答える
-3

まず、遅延読み込みをオンにします。

2番目:取得して返すものをフィルタリングする場合は、カスタムの戻りオブジェクトなどを実行します。

from u in db.Users
join r in db.Roles
  on u.RoleID equals r.RoleID
select new { u.UserID, u.Title, u.Email, r.RoleName }

またはそのようなもの。最小限の戻りオブジェクトがあり、オブジェクトグラフは小さくなります。

于 2012-12-03T21:58:46.643 に答える