EF Core - Select()のナビゲーションプロパティにアクセスできません

c# entity-framework-core

質問

IdentityUserモデルのナビゲーションロールのプロパティにアクセスしようとしています。

GetQueryable関数の中でincludeプロパティを設定しています

protected virtual IQueryable<TEntity> GetQueryable<TEntity>(
    Expression<Func<TEntity, bool>> filter = null,
    string includeProperties = null
    )
    where TEntity : class, IEntity
    {
        IQueryable<TEntity> query = context.Set<TEntity>();
        if (filter != null)
        {
            query = query.Where(filter);
        }

        if (includeProperties != null)
        {
            query = query.Include(includeProperties);
        }
        return query;
    }

次のクエリを実行すると、rolesプロパティが正常に設定されます。

return GetQueryable<ApplicationUser>(e => e.Id == id, "Roles").SingleOrDefault();

しかし、以下のDtoで投影(選択)を使うときは:

public class ApplicationUserDto: BaseDto
{
    public string Email { get; set; }
    public string Name { get; set; }
    public List<IdentityUserRole<string>> Roles{ get; set; }

    public static Expression<Func<ApplicationUser, ApplicationUserDto>> SelectProperties = (user) => new ApplicationUserDto {
        Id = user.Id,
        Email = user.Email,
        Name = user.Name,
        Roles = (List<IdentityUserRole<string>>)user.Roles
    };
}

次に、次のクエリがクラッシュします。

return GetQueryable<ApplicationUser>(e => e.Id == id, "Roles").Select(ApplicationUserDto.SelectProperties).SingleOrDefault();

次のエラーが表示されます。

System.InvalidOperationException: The type of navigation property 'Roles' on the entity type 'IdentityUser<string, IdentityUserClaim<string>, IdentityUserRole
<string>, IdentityUserLogin<string>>' is 'ICollection<IdentityUserRole<string>>' for which it was not possible to create a concrete instance. Either initialize the
property before use, add a public parameterless constructor to the type, or use a type which can be assigned a HashSet<> or List<>.

また、警告を記録します。

warn: Microsoft.EntityFrameworkCore.Query.RelationalQueryCompilationContextFactory[6]
      The Include operation for navigation: 'user.Roles' was ignored because the target navigation is not reachable in the final query results. 

受け入れられた回答

実際には、EF Core 1.1では、 Select()を使うとIncludeは無視され、以下を参照してください:

無視されるセクションは次のとおりです 。https : //docs.microsoft.com/en-us/ef/core/querying/related-data

それが警告を表示していた理由です:

warn: Microsoft.EntityFrameworkCore.Query.RelationalQueryCompilationContextFactory[6]
      The Include operation for navigation: 'user.Roles' was ignored because the target navigation is not reachable in the final query results.

ToList()も機能しませんでした。そのためには、ナビゲーションプロパティで別の投影が必要でした。

    public static Expression<Func<ApplicationRole, ApplicationRoleDto>> SelectProperties = (role) => new ApplicationRoleDto
    {
        Id = role.Id,
        Name = role.Name.Substring(0, role.Name.Length - role.TenantId.Length),
        Description = role.Description,
        // another projection on Claims navigation property
        Claims = role.Claims.Select(claim => claim.ClaimValue).ToList(),
    };

注意:リストにSelect()を使用すると(Include()が無視されるので)熱心な読み込みが発生しないため、各要素のナビゲーションプロパティを取得するために個別のSQLクエリが生成されるため、結果セットに含まれます。

一方、 Include() のみを使用すると、期待どおりに結合が行われ、より良い結果が得られます。


人気のある回答

それをあなたのDTOに割り当てるには、具体化(ロールを明示的に収集するサブクエリを実行する必要があります)

public class ApplicationUserDto: BaseDto
{
    public string Email { get; set; }
    public string Name { get; set; }
    public List<IdentityUserRole<string>> Roles{ get; set; }

    public static Expression<Func<ApplicationUser, ApplicationUserDto>> SelectProperties = (user) => new ApplicationUserDto {
        Id = user.Id,
        Email = user.Email,
        Name = user.Name,
        Roles = user.Roles.ToList()
    };
}

追加することを忘れないでください: using System.Linq; ICollection .ToList()を呼び出せるようにするためにファイルに.ToList()します。

コメントで述べたように、必要な型は文字列なので、 user.Rolesで何かをすることができます。

user.Roles.Select(role=> role.RoleId).ToList()

後で結果を具体化することを忘れないでください。



Related

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ