How To Transform A Class Into DataSource

I wanted to share this tip because I feel some Visual Studio features look like magic. In this tip, you'll see how to convert a C# class into a DataSource.
 
DataSources are objects and objects are classes. Transforming a class into a DataSource is great because it allows you to use LINQ to enumerate and read the data. This is also useful when you create a report or need to have access to individual records in DataRow formats. So, take a class with the data definition and with custom properties and add a key to the class to make it appear as a DataSource.
 
Let's start by creating a class. By assigning some attributes to a class, you're telling the compiler to make it a data object. In the following code, we add a DataObjectAttribute to a partial class and also make it serializable. 
  1. using System.ComponentModel;  
  2.   
  3. [System.Serializable]  
  4. [DataObjectAttribute]  
  5. public partial class ReportProcessosEAndamentos  
  6. {  
  7.   public int ID { get; set; }
  8.   public string Name { get; set; }
  9.   pubblic string MyData => MyCustomDataTransforms(); // You can process fields from the table or project
  10.  // ANY OTHERS PROPERTIES
  11.  // You can Add readonly property using private:
  12. public int MyReadOnlyProperty { get; private set; }
  13.   
  14. }  
Now, we need to add a property to the function that will load the DataSource and retrieve a data list.
 
[DataObjectMethodAttribute(DataObjectMethodType.Select, true)] 
  1. [DataObjectMethodAttribute(DataObjectMethodType.Select, true)]  public static IEnumerable<BIExportData> GetList()         
  2.          => FillData(ConnectionString);  
Here is a full sample from my real app www.Advocati.NET.
  1. using System;  
  2. using System.Text;  
  3. using System.Data;  
  4. using System.Xml.Serialization;  
  5. using System.Collections.Generic;  
  6. using MenphisSI.DB;  
  7. using System.Data.SqlClient;   
  8. using System.ComponentModel; // Add Componente Model 01  
  9.   
  10. namespace MenphisSI.GerAdv  
  11. {  
  12.     /// <summary>  
  13.     /// Objeto de nível de acesso a dados  
  14.     /// </summary>  
  15.     [System.Serializable]     
  16.     [DataObjectAttribute] // This Attribute in the top of the class 02  
  17.     // ReSharper disable once InconsistentNaming  
  18.     public partial class DBAcao : VAuditor, ICadastros  
  19.     {  
  20.   
  21.         private string m_FDescricao;  
  22.   
  23.         [XmlAttribute]  
  24.         public int ID {get;set;}  
  25.         [XmlAttribute]        
  26.         public string FDescricao  
  27.         {  
  28.             get => m_FDescricao ?? string.Empty;  
  29.             set => m_FDescricao = value;              
  30.         }  
  31.   
  32.         public DBAcao() { }  
  33.          
  34.   
  35.         /// <summary>  
  36.         /// Lista a tabela  
  37.         /// </summary>  
  38.         /// <param name="cWhere"></param>  
  39.         /// <param name="cOrder"></param>  
  40.         /// <param name="cCnn"></param>  
  41.         /// <param name="nTop">/param>  
  42.         /// <returns></returns>  
  43.         [DataObjectMethodAttribute(DataObjectMethodType.Select, true)]  // Add this property to be the readable entry point  
  44.         public static IEnumerable<DBAcao> Listar(string cWhere, string cOrder, string cCnn, int nTop = 0)  
  45.         {  
  46.             var cSql = new StringBuilder(TSql.Select);  
  47.             if (nTop > 0) cSql.Append($" TOP {nTop} ");  
  48.             cSql.Append(DBAcao.CamposSqlX);  
  49.             cSql.Append(TSql.From);  
  50.             cSql.Append($"[dbo].[{DBAcao.PTabelaNome}] ");  
  51.             if (cWhere.NotIsEmpty())  
  52.             {  
  53.                 if (cWhere.NãoContemUpper(TSql.Where)) cSql.Append(TSql.Where);  
  54.                 cSql.Append(cWhere);  
  55.             }  
  56.             if (cOrder.NotIsEmpty())  
  57.             {  
  58.                 if (cOrder.NãoContemUpper(TSql.OrderBy))  
  59.                     cSql.Append($"{TSql.OrderBy} {cOrder}");  
  60.                 else  
  61.                     cSql.Append(cOrder);  
  62.             }  
  63.             else if (DBAcao.CampoNome.NotIsEmpty())  
  64.             {  
  65.                 cSql.Append($"{TSql.OrderBy}{DBAcao.CampoNome}");  
  66.             }  
  67.             DataTable ds;  
  68.             try  
  69.             {  
  70.                 using (var oCnn = ConfiguracoesDBT.GetConnection(cCnn))  
  71.                 {  
  72.                     if (oCnn is null) yield break;  
  73.                     ds = ConfiguracoesDBT.GetDataTable(cSql.ToString(), oCnn);  
  74.                 }  
  75.             }  
  76.             catch { yield break; }  
  77.             if (ds.Rows.Count <= 0) yield break;  
  78.             for (var nt = 0; nt < ds.Rows.Count; nt++)  
  79.                 yield return new DBAcao  
  80.                 {  
  81.                     ID = Convert.ToInt32(ds.Rows[nt][DBAcaoDicInfo.CampoCodigo]),  
  82.                     FDescricao = ds.Rows[nt][DBAcaoDicInfo.Descricao].ToString(),  
  83.                   };  
  84.         }  
  85.     }  
Note that "yield return" is a powerful command that will return the object directly to the IEnumerable list instead of crerating a list and return it in the end of the function/method.
 
Now, let's take a look at the sample using Telerik as Object DataSource and how to use it.
 
Open the DataSource.
 
 
Name it, and choose your load method, mark to get only. 
 
 
To use the class, you need to populate with data.
 
How to use your "new" data component source is up to you.
 
Good luck!