Render tabel dengan Entity Framework

Ada sejumlah tugas ketika untuk beberapa alasan lebih nyaman untuk mengekspor data dari basis data ke dokumen PDF tanpa menggunakan skema konversi HTML ke PDF yang baru-baru ini populer.

Artikel ini akan menunjukkan kepada Anda cara menghasilkan dokumen PDF menggunakan Aspose.PDF for .NET.

Dasar-dasar generasi PDF dengan Aspose.PDF

Salah satu kelas terpenting dalam Aspose.PDF adalah Kelas Document. Kelas ini adalah mesin rendering PDF. Untuk menyajikan struktur PDF, pustaka Aspose.PDF menggunakan model Document-Page, di mana:

  • Document - berisi properti dokumen PDF termasuk koleksi halaman.
  • Page - berisi properti halaman tertentu dan berbagai koleksi elemen yang terkait dengan halaman ini.

Oleh karena itu, untuk membuat dokumen PDF dengan Aspose.PDF, Anda harus mengikuti langkah-langkah berikut:

  1. Buat objek Document.
  2. Tambahkan halaman (objek Page) untuk objek Document.
  3. Buat objek yang ditempatkan di halaman (misalnya fragmen teks, tabel, dll.).
  4. Tambahkan item yang dibuat ke koleksi yang sesuai di halaman (dalam kasus kami ini akan menjadi koleksi paragraf).
  5. Simpan dokumen sebagai file PDF.

Masalah yang paling umum adalah output data dalam format tabel. Kelas Table digunakan untuk memproses tabel. Kelas ini memberi kita kemampuan untuk membuat tabel dan menempatkannya dalam dokumen, menggunakan Rows dan Cells. Jadi, untuk membuat tabel, Anda perlu menambahkan jumlah baris yang diperlukan dan mengisinya dengan jumlah sel yang sesuai.

Contoh berikut membuat tabel 4x10.

Saat menginisialisasi objek Table, pengaturan kulit minimal digunakan:

Sebagai hasilnya, kami mendapatkan tabel 4x10 dengan kolom lebar yang sama.

Tabel 4x10

Mengekspor Data dari Objek ADO.NET

Kelas Table menyediakan metode untuk berinteraksi dengan sumber data ADO.NET - ImportDataTable dan ImportDataView. Metode pertama mengimpor data dari DataTable, yang kedua dari DataView. Dengan premis bahwa objek-objek ini tidak terlalu nyaman untuk bekerja dalam template MVC, kami akan membatasi diri pada contoh singkat. Dalam contoh ini (baris 50), metode ImportDataTable dipanggil dan menerima sebagai parameter sebuah instance DataTable dan pengaturan tambahan seperti flag header dan posisi awal (baris/kolom) untuk output data.

Mengekspor Data dari Entity Framework

Lebih relevan untuk .NET modern adalah impor data dari kerangka ORM. Dalam hal ini, ada baiknya untuk memperluas kelas Table dengan metode ekstensi untuk mengimpor data dari daftar sederhana atau dari data yang dikelompokkan. Mari kita berikan contoh untuk salah satu ORM yang paling populer - Entity Framework.

public static class PdfHelper
{
    private static void ImportEntityList<TSource>(this Aspose.Pdf.Table table, IList<TSource> data)
    {
        var headRow = table.Rows.Add();

        var props = typeof(TSource).GetProperties(BindingFlags.Public | BindingFlags.Instance);
        foreach (var prop in props)
        {
            headRow.Cells.Add(prop.GetCustomAttribute(typeof(DisplayAttribute)) is DisplayAttribute dd ? dd.Name : prop.Name);
        }

        foreach (var item in data)
        {
            // Add row to table
            var row = table.Rows.Add();
            // Add table cells
            foreach (var t in props)
            {
                var dataItem = t.GetValue(item, null);
                if (t.GetCustomAttribute(typeof(DataTypeAttribute)) is DataTypeAttribute dataType)
                    switch (dataType.DataType)
                    {

                        case DataType.Currency:
                            row.Cells.Add(string.Format("{0:C}", dataItem));
                            break;
                        case DataType.Date:
                            var dateTime = (DateTime)dataItem;
                            if (t.GetCustomAttribute(typeof(DisplayFormatAttribute)) is DisplayFormatAttribute df)
                            {
                                row.Cells.Add(string.IsNullOrEmpty(df.DataFormatString)
                                    ? dateTime.ToShortDateString()
                                    : string.Format(df.DataFormatString, dateTime));
                            }
                            break;
                        default:
                            row.Cells.Add(dataItem.ToString());
                            break;
                    }
                else
                {
                    row.Cells.Add(dataItem.ToString());
                }
            }
        }
    }

    private static void ImportGroupedData<TKey, TValue>(this Aspose.Pdf.Table table, IEnumerable<Models.GroupViewModel<TKey, TValue>> groupedData)
    {
        var headRow = table.Rows.Add();
        var props = typeof(TValue).GetProperties(BindingFlags.Public | BindingFlags.Instance);
        foreach (var prop in props)
        {
            headRow.Cells.Add(prop.GetCustomAttribute(typeof(DisplayAttribute)) is DisplayAttribute dd ? dd.Name : prop.Name);
        }

        foreach (var group in groupedData)
        {
            // Add group row to table
            var row = table.Rows.Add();
            var cell = row.Cells.Add(group.Key.ToString());
            cell.ColSpan = props.Length;
            cell.BackgroundColor = Aspose.Pdf.Color.DarkGray;
            cell.DefaultCellTextState.ForegroundColor = Aspose.Pdf.Color.White;

            foreach (var item in group.Values)
            {
                // Add data row to table
                var dataRow = table.Rows.Add();
                // Add cells
                foreach (var t in props)
                {
                    var dataItem = t.GetValue(item, null);

                    if (t.GetCustomAttribute(typeof(DataTypeAttribute)) is DataTypeAttribute dataType)
                        switch (dataType.DataType)
                        {
                            case DataType.Currency:
                                dataRow.Cells.Add(string.Format("{0:C}", dataItem));
                                break;
                            case DataType.Date:
                                var dateTime = (DateTime)dataItem;
                                if (t.GetCustomAttribute(typeof(DisplayFormatAttribute)) is DisplayFormatAttribute df)
                                {
                                    dataRow.Cells.Add(string.IsNullOrEmpty(df.DataFormatString)
                                        ? dateTime.ToShortDateString()
                                        : string.Format(df.DataFormatString, dateTime));
                                }
                                break;
                            default:
                                dataRow.Cells.Add(dataItem.ToString());
                                break;
                        }
                    else
                    {
                        dataRow.Cells.Add(dataItem.ToString());
                    }
                }
            }
        }
    }
}

Atribut Data Annotations sering digunakan untuk mendeskripsikan model dan membantu kita untuk membuat tabel. Oleh karena itu, algoritma pembuatan tabel berikut dipilih untuk ImportEntityList:

  • baris 12-18: membangun baris header dan menambahkan sel header sesuai dengan aturan “Jika DisplayAttribute ada, maka ambil nilainya jika tidak ambil nama propertinya”.
  • baris 50-53: membangun baris data dan menambahkan sel baris sesuai dengan aturan “Jika atribut DataTypeAttribute didefinisikan, maka kita memeriksa apakah kita perlu membuat pengaturan desain tambahan untuknya, dan jika tidak, cukup konversi data ke string dan tambahkan ke sel;”.

Dalam contoh ini, penyesuaian tambahan dilakukan untuk DataType.Currency (baris 32-34) dan DataType.Date (baris 35-43), tetapi Anda dapat menambahkan yang lain jika perlu. Algoritma metode ImportGroupedData hampir sama dengan yang sebelumnya. Kelas tambahan GroupViewModel digunakan, untuk menyimpan data yang dikelompokkan.

using System.Collections.Generic;
public class GroupViewModel<K,T>
{
    public K Key;
    public IEnumerable<T> Values;
}

Karena kita memproses grup, pertama kita menghasilkan baris untuk nilai kunci (baris 66-71), dan setelah itu - baris dari grup ini.