Saya tidak dapat menemukan contoh di mana Anda dapat mengecualikan bidang secara kondisional berdasarkan variabel dalam proyeksi terpilih di LINQ, lihat juga LINQ: Pilih objek dan ubah beberapa properti tanpa membuat objek baru.

Biarkan saya memberikan beberapa latar belakang tentang apa yang saya coba capai. Saya ingin membatasi beberapa bidang di DTO yang disetel dari model berdasarkan apakah pengguna dapat mengedit data (yaitu bidang komentar). Misalnya, pilih berikut dengan delegasi bernama CustomerView.

var qry = _ctx.Customer.Select(CustomerView(User.IsInRole("Editor")));

Model Pelanggan memiliki properti navigasi Pesanan dan fungsi berikut mengubah data menjadi DTO CusomerViewModel.

private Expression<Func<Customer, CustomerViewModel>> CustomerView(bool isEditor) {
    return c => new CustomerViewModel
    {
        Id = c.Id,
        Name = c.Name,
        Comment = isEditor ? c.Comment : null,
        OrderCount = c.Orders.Count()
    };
}

Ini akan menghasilkan SQL seperti CASE WHEN @__isEditor_0 = TRUE THEN Comment ELSE NULL yang berfungsi, tetapi saya lebih suka ekspresi tidak dibuat, yaitu bidang dibiarkan sebagai default. Itu adalah kasus penggunaan yang sederhana, tetapi jika saya ingin melakukan hal yang sama dengan bidang OrderCount, subquery SQL akan tetap disertakan.

Tentu saja saya dapat membuat fungsi lain untuk pengguna non-editor yang mengecualikan bidang tertentu, tetapi saya lebih suka tidak memiliki proyeksi terpisah untuk dipertahankan terutama ketika mereka lebih kompleks.

Saya melihat pertanyaan di mana LINQ dinamis digunakan untuk klausa mana tetapi tidak banyak untuk dipilih. Apakah pendekatan ini layak?

Edit: Apakah ada cara untuk menghapus bidang secara manual dari pohon ekspresi setelah pilihan digunakan, mungkin melalui metode ekstensi?

0
Mark G 11 Maret 2020, 03:12

1 menjawab

Jawaban Terbaik

Menggunakan LINQKit Saya dapat mencapai hasil yang diinginkan dengan menambahkan AsExpandable() untuk memilih.

var qry = _ctx.Customer.AsExpandable().Select(CustomerView(User.IsInRole("Editor")));

Kemudian tambahkan ekspresi untuk bidang komentar dan panggil Invoke() pada tugas bidang.

private Expression<Func<Customer, CustomerViewModel>> CustomerView(bool isEditor) {
    Expression<Func<Customer, string>> exprComment;
    if (isEditor)
        exprComment = c => c.Comment;
    else
        exprComment = c => null;

    return c => new CustomerViewModel
    {
        Id = c.Id,
        Name = c.Name,
        Comment = exprComment.Invoke(c),
        OrderCount = c.Orders.Count()
    };
}

Tampaknya berhasil, tetapi saya masih tertarik untuk mendengar pendekatan alternatif apa pun.

0
Mark G 12 Maret 2020, 04:03