C# class library, access object properties - c#

I have a function which suppose to receive an object as parameter and use its properties for further use,but when i try to access object properties it mark them as red (can't resolve symbol...)
i tried to add few references but it didn't help.
public bool InsertStudent(object student)
{
var db = DAL.Services.SqlServicesPool.HackService;
using (var connection = db.StartConnection())
{
var sqlParam = new SqlParameter[]
{
new SqlParameter("#Name", student.Name),
new SqlParameter("#Lname", student.Lname),
new SqlParameter("#Phone", student.Phone),
new SqlParameter("#Email", student.Email),
new SqlParameter("#Img", student.Img),
new SqlParameter("#CityId", student.CityId)
};
var result = db.Exec(connection, "spInsertNewStudent", sqlParam);
db.StopConnection(connection);
return result;
};
}

The type of student is object, or more formally System.Object. This type hasn't any property called Name or Lname etc. That's the problem. You should change the type to the class used to create the student object. For instance if you have created the Student object like below:
var student = new Student
{
Name = "foo"
// .....
}
You should change the signature of your method like below:
public bool InsertStudent(Student student)

Parameter 'student' has an 'Object' type. This is base type for all classes and structures. You should cast 'student' to your class type
public bool InsertStudent(object obj)
{
var student = (Student)obj;
....
}
Or change 'student' parameter type
public bool InsertStudent(Student student)
{
....
}

Use Student class insted of object class
public bool InsertStudent(Student student)
{
var db = DAL.Services.SqlServicesPool.HackService;
using (var connection = db.StartConnection())
{
var sqlParam = new SqlParameter[]
{
new SqlParameter("#Name", student.Name),
new SqlParameter("#Lname", student.Lname),
new SqlParameter("#Phone", student.Phone),
new SqlParameter("#Email", student.Email),
new SqlParameter("#Img", student.Img),
new SqlParameter("#CityId", student.CityId)
};
var result = db.Exec(connection, "spInsertNewStudent", sqlParam);
db.StopConnection(connection);
return result;
};
}
public class Student
{
public string Name { get; set; }
public string Lname { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public byte []Img { get; set; }
public string CityId { get; set; }
}
or
public bool InsertStudent((Student)object student){ ... }

As Christos commented, you need to use a Student object rather.
public class Student
{
public string Name { get; set; }
public string Lname { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public string Image { get; set; } //Wasn't sure what type you use here
public int CityId { get; set; }
}
Then pass through a Student object as your parameter.
public bool InsertStudent(Student student)
{
var db = DAL.Services.SqlServicesPool.HackService;
using (var connection = db.StartConnection())
{
var sqlParam = new SqlParameter[]
{
new SqlParameter("#Name", student.Name),
new SqlParameter("#Lname", student.Lname),
new SqlParameter("#Phone", student.Phone),
new SqlParameter("#Email", student.Email),
new SqlParameter("#Img", student.Img),
new SqlParameter("#CityId", student.CityId)
};
var result = db.Exec(connection, "spInsertNewStudent", sqlParam);
db.StopConnection(connection);
return result;
};
}

Related

Dapper - How to create class instance by column value?

How to instantiate class by specific column value with Dapper?
Let's say we have table 'items' with columns: ID, Type, Name...
And, when Type is equal to "Burger", class Burger should be instantiated, when Type is "Sandwich", class Sandwich should be instantiated.
First approach that comes to my mind is to execute query for every type, for example:
var sandwiches = conn.Query<Sandwich>("SELECT * FROM items WHERE Type = 'Sandwich'");
var burgers = conn.Query<Burger>("SELECT * FROM items WHERE Type = 'Burger'");
But this approach is expensive because we will have as many queries as number of item types.
Can we do the same job with single query? (Select all rows and create instances based on column value)
A class could have a generic method that could do what you want:
public class Query
{
public IEnumerable<T> GenericQuery<T>(string query)
{
using (SqlConnection cnn = new SqlConnection("Data Source=(LOCAL);Initial Catalog=LinqPadTest;Integrated Security=True;"))
{
cnn.Open();
return cnn.Query<T>(query);
}
}
}
Now you can call it in this way
void Main()
{
var q = new Query();
var sandwiches = q.GenericQuery<Sandwich>("SELECT * FROM items WHERE Type = 'Sandwich'");
var burgers = q.GenericQuery<Burger>("SELECT * FROM items WHERE Type = 'Burger'");
}
use method's generic argument to get type
public class ItemsRepository
{
private const string Query = "SELECT * FROM items WHERE Type = #Type";
public async Task<IEnumerable<T>> GetItemsBasedOnTypeAsync<T>()
{
await using var connection = new SqlConnection("Data Source=(LOCAL);Initial Catalog=LinqPadTest;Integrated Security=True;");
await connection.OpenAsync();
var parameters = new { Type = nameof(T) };
return connection.Query<T>(Query, parameters);
}
}
now you can call method for any items type
var itemsRepository = new ItemsRepository();
var sandwiches = await itemsRepository.GetItemsBasedOnTypeAsync<Sandwich>();
var burgers = await itemsRepository.GetItemsBasedOnTypeAsync<Burger>();
V2(select all items):
use can do something like this, or cast to base interface if exists.
public class Item
{
public int Id { get; set; }
public string Type { get; set; }
public int Property1 { get; set; }
public int Property2 { get; set; }
}
public class Sandwich
{
public Sandwich(Item item)
{
Id = item.Id;
Property1 = item.Property1;
Property2 = item.Property2;
}
public int Id { get; set; }
public int Property1 { get; set; }
public int Property2 { get; set; }
}
public class Burger
{
public Burger(Item item)
{
Id = item.Id;
Property1 = item.Property1;
Property2 = item.Property2;
}
public int Id { get; set; }
public int Property1 { get; set; }
public int Property2 { get; set; }
}
public class ItemsRepository
{
private const string Query = "SELECT * FROM items";
public async Task<IEnumerable<object>> GetItemsBasedOnTypeAsync()
{
await using var connection = new SqlConnection("Data Source=(LOCAL);Initial Catalog=LinqPadTest;Integrated Security=True;");
await connection.OpenAsync();
var items = connection.Query<Item>(Query);
var objects = items.Select(Create)
.ToList();
return objects;
}
private object? Create(Item item) =>
Assembly
.GetExecutingAssembly()
.CreateInstance(item.Type,true,BindingFlags.Public,null,
new object[]{item},
CultureInfo.DefaultThreadCurrentCulture, null);
}

C# generic insert method to insert object into Sqlite3 table?

I am trying to make a generic method where I can insert any object into a sqlite3 database.
User class:
public class Users : IClassModel<Users>
{
public int Id { get; set; }
public string UserName { get; set; }
public string UserAddress { get; set; }
public string OtherUserDetails { get; set; }
public decimal AmountOfFine { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
}
Interface class:
public interface IClassModel<T>
{
public int Id { get; set; }
}
QueryBuilder class:
public class queryBuilder : IDisposable
{
private SqliteConnection _connection;
public queryBuilder(string connectionString)
{
_connection = new SqliteConnection(connectionString);
_connection.Open();
}
public void Dispose()
{
_connection.Close();
}
public void Create<T>(T obj) where T : IClassModel<T>
{
// insert into tableName values()
Type myType = obj.GetType();
IList<PropertyInfo> props = new List<PropertyInfo>(myType.GetProperties());
ArrayList valueArray = new ArrayList();
ArrayList nameArray = new ArrayList();
var questionString = "";
var nameString = "";
foreach (PropertyInfo prop in props)
{
object propValue = prop.GetValue(obj, null);
object propName = prop.Name;
valueArray.Add(propValue);
nameArray.Add(propName);
questionString += "?, ";
nameString += $"{propName}, " ;
}
var newNameString = nameString.Trim();
var newerNameString = newNameString.TrimEnd(',');
var newQuestionString = questionString.Trim();
var newerQuestionString = newQuestionString.TrimEnd(',');
SqliteCommand insertSQL = new SqliteCommand($"INSERT INTO {typeof(T).Name} ({newerNameString}) VALUES ({newerQuestionString})", _connection);
foreach (var item in valueArray)
{
insertSQL.Parameters.Add(item);
}
insertSQL.ExecuteNonQuery();
//Console.WriteLine("Successfully added the thing.");
}
}
Driver:
using Microsoft.Data.Sqlite;
using QueryBuilder.Models;
using System.Reflection;
using (var query = new queryBuilder(#"Data Source=C:\path\to\database"))
{
// con
var user = new Users();
user.UserName = "username";
user.UserAddress = "some_address";
user.OtherUserDetails = "details";
user.AmountOfFine = 90;
user.Email = "something#email.com";
user.PhoneNumber = "5555555555";
query.Create<Users>(user);
}
I know my code is bit messy, but the idea is to somehow create an object and then be able to insert it into the already made table, no matter what object it is. I keep getting invalid cast exceptions.
I need to be able to iterate through the values and properties and add them to the sqlite insert command but it doesn't seem to be working. Any help is appreciated.

How do I extend a model class to another model?

I am trying to extend a class to another class that will collect them as a list.
model:
public class Brand
{
public int BrandId { get; set; }
public string Name { get; set; }
public string Guid { get; set; }
public float Rating { get; set; }
public string Industry { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Postal { get; set; }
public string CountryCode { get; set; }
public virtual Snapshot Snapshot { get; set; }
}
public class Snapshot
{
public int ID { get; set; }
public string Guid { get; set; }
public int CompanyID { get; set; }
public string CompanyName { get; set; }
public string Email { get; set; }
public DateTime DateTimeSent { get; set; }
public string Subject { get; set; }
public string Html { get; set; }
public string Image { get; set; }
public string Unsubscribe { get; set; }
}
public class BrandSnaphotViewModel
{
public Brand Brand { get; set; }
public List<Snapshot> SnapshotItems { get; set; }
}
controller:
public ActionResult Index(string brandGuid)
{
BrandSnaphotViewModel viewModel = new BrandSnaphotViewModel();
Brand brand = GetBrand(brandGuid);
viewModel.Brand = brand;
List<Snapshot> snapshot = GetBrandSnapshots(brand.BrandId);
viewModel.SnapshotItems = snapshot;
List<BrandSnaphotViewModel> viewModelList = new List<BrandSnaphotViewModel>();
viewModelList.Add(viewModel);
return View(viewModelList.AsEnumerable());
}
private Brand GetBrand(string brandGuid)
{
Brand brand = new Brand();
string dbConnString = WebConfigurationManager.ConnectionStrings["dbConn"].ConnectionString;
MySqlConnection dbConn = new MySqlConnection(dbConnString);
dbConn.Open();
MySqlCommand dbCmd = new MySqlCommand();
dbCmd.CommandText = "SELECT *, industries.name AS industry_name FROM brands LEFT JOIN industries ON brands.industry_id = industries.industry_id WHERE brand_guid = '" + brandGuid.ToString() + "' AND private = 0 LIMIT 1";
dbCmd.Connection = dbConn;
MySqlDataReader dbResult = dbCmd.ExecuteReader();
if (dbResult.Read())
{
brand.Guid = dbResult["brand_guid"].ToString();
brand.BrandId = Convert.ToInt32(dbResult["brand_id"]);
brand.Industry = dbResult["industry_name"].ToString();
}
dbResult.Close();
dbConn.Close();
return brand;
}
private List<Snapshot> GetBrandSnapshots(int brandId)
{
string dbConnString = WebConfigurationManager.ConnectionStrings["dbConn"].ConnectionString;
MySqlConnection dbConn = new MySqlConnection(dbConnString);
dbConn.Open();
MySqlCommand dbCmd = new MySqlCommand();
dbCmd.CommandText = "SELECT * FROM snapshots WHERE brand_id = " + brandId + " AND archive = 0 ORDER BY date_sent DESC";
dbCmd.Connection = dbConn;
MySqlDataReader dbResult = dbCmd.ExecuteReader();
List<Snapshot> snapshots = new List<Snapshot>();
while (dbResult.Read())
{
snapshots.Add(new Snapshot
{
SnapshotId = Convert.ToInt32(dbResult["snapshot_id"]),
Subject = dbResult["subject"].ToString(),
DateTimeSent = Convert.ToDateTime(dbResult["date_sent"]),
Image = dbResult["image"].ToString(),
Email = dbResult["email"].ToString(),
ContentType = dbResult["content_type"].ToString(),
Type = dbResult["type"].ToString()
});
}
dbResult.Close();
dbConn.Close();
return snapshots;
}
edit
FIXED
The issue was the VIEW was not referencing the ViewModel as an IENumerable<>. FACEPALM.
#model IEnumerable<projectvia.ViewModels.BrandSnaphotViewModel>
#{
ViewBag.Title = "Index";
}
#foreach(var item in Model)
{
#item.Brand.Guid;
for(int i = 0; i< #item.SnapshotItems.Count; i++)
{
#item.SnapshotItems[i].Subject<br/>
}
}
That resolved the issue.
Thank you both experts for the insights... i took both advice and came to this solution.
you are doing wrong, it is a list.
you cannot add element this way. Create object and add that object in list by calling Add()
do like this to add items in it:
List<BrandEmailList> brandSnapshotsList = new List<BrandEmailList>();
while (dbResult.Read())
{
BrandEmailList brandSnapshots = new BrandEmailList (); // create an object
brandSnapshots.ID = Convert.ToInt32(dbResult["snapshot_id"]);
brandSnapshots.Guid = dbResult["snapshot_guid"].ToString();
brandSnapshots.DateTimeSent = dbResult["date_sent"];
brandSnapshots.Subject = dbResult["subject"].ToString();
brandSnapshots.Image = dbResult["image"];
brandSnapshotsList.Add(brandSnapshots); // add it in list
}
EDIT:
List is a generic thing, you don't need to create a class for it. you can just instantiate a list and add items in it.
why are you doing like that you can do it this way simply:
List<Snapshot> brandSnapshotsList = new List<Snapshot>();
while (dbResult.Read())
{
Snapshot brandSnapshots = new Snapshot(); // create an object
brandSnapshots.ID = Convert.ToInt32(dbResult["snapshot_id"]);
brandSnapshots.Guid = dbResult["snapshot_guid"].ToString();
brandSnapshots.DateTimeSent = dbResult["date_sent"];
brandSnapshots.Subject = dbResult["subject"].ToString();
brandSnapshots.Image = dbResult["image"];
brandSnapshotsList.Add(brandSnapshots); // add it in list
}
Building on what Ehsan Sajjad did, looking at public IEnumerator<Snapshot> BrandEmails, i believe what you look for looks more like this:
public class Snapshot
{
public int ID { get; set; }
public string Guid { get; set; }
// ...
}
public class BrandEmailList : List<Snapshot>
{
}
You need not even create a new type for your brand email list, you can use List<Snapshot> directly.
public ViewResult Whatever() {
var brand = GetBrand(brandName);
var brandSnapshots = GetBrandSnapshots();
return View(brand, brandSnapshots);
}
private Brand GetBrand(string brandName)
{
try
{
var brand = new Brand();
brand.Name = brandName;
// database stuffs ...
return brand;
}
catch (Exception ex)
{
throw ex;
}
}
private List<Snapshot> GetBrandSnapshots()
{
// ...
// DB stuffs -- that *really* should not be in the controller anyways.
// ...
var snapshots = new List<BrandEmailList>();
while (dbResult.Read())
{
// object initializer syntax
snapshots.Add(new Snapshot {
ID = Convert.ToInt32(dbResult["snapshot_id"]),
Guid = dbResult["snapshot_guid"].ToString(),
DateTimeSent = dbResult["date_sent"],
Subject = dbResult["subject"].ToString(),
Image = dbResult["image"],
});
}
return snapshots
}
As a side note, mixing database access into controller methods can be a bad idea. It does not have to be, but it can be. Generally, fetching data from the database happens at a different "level" than serving a MVC result. MVC controller don't have the "purpose" to talk to a database, that work can/should be delegated to a dedicated type. Compare the single responsibility principle part of the SOLID principles.

Seed list inside an empty list

I'm working with KnockoutMVC and it requires strongly type models to use inside the VIEW. I have tried multiple variations of the examples on KnockoutMVC's site including using ENUMS and still could not get it to work. Perhaps this is a problem with the setup of my models.
MODELS
public class PhoneNumber
{
public List<NumberTypeClass> Types { get; set; }
//public NumberType enumType { get; set; }
//public enum NumberType
//{
// Work,
// Home,
// Mobile,
// Fax
//}
private string _number;
[StringLength(14, MinimumLength = 10, ErrorMessage = "Please use (123) 456-7890 format"), Required]
public string Number
{
get
{
this._number = BeautifyPhoneNumber(this._number);
return this._number;
}
set
{
this._number = value;
}
}
public string Extension { get; set; }
public static String BeautifyPhoneNumber(string numberToBeautify)
{
//beautifyNumberCode
}
}
public class NumberTypeClass
{
public int Id { get; set; }
public string NumberType { get; set; }
}
public class VendorsEditorVendorModel
{
public string FirstName {Get;set;}
public string LastName {get;set;}
public List<Address> Address {get;set;}
public List<PhoneNumber> Phones {get;set;}
}
public class VendorsEditorModel
{
public List<VendorsEditorVendorModel> Vendors {get;set;}
}
CONTROLLER
public class VendorsEditorController : BaseController
{
public ActionResult CreateVendors()
{// VendorsEditor/CreateVendors
var vendor = new VendorsEditorModel();
vendor.Vendors = new List<VendorsEditorVendorModel>();
vendor.Vendors[0].Phones[0].Types = new List<NumberTypeClass>
{
new NumberTypeClass{Id = 0, TypeName = "Mobile"},
new NumberTypeClass{Id = 0, TypeName = "Work"},
new NumberTypeClass{Id = 0, TypeName = "Home"}
};//this throws an error because there is no Vendors[0] ...but how would i populate this list for every Vendor?
return View(vendor);
}
}
You cannot call an empty collection by index [x]. You need to fill your collection from a database or what not before you can access items in it. If you are just trying to add items to a collection, this is how you do it:
var vendor = new VendorsEditorModel
{
Vendors = new List<VendorsEditorVendorModel>
{
new VendorsEditorVendorModel
{
Phones = new List<PhoneNumber>
{
new PhoneNumber
{
Types = new List<NumberTypeClass>
{
new NumberTypeClass {Id = 0, NumberType = "Mobile"}
}
}
}
}
}
};
If you just want to add the types to an already populated collection, you can do the following:
foreach (var phone in vendor.Vendors.SelectMany(item => item.Phones))
{
phone.Types = new List<NumberTypeClass>
{
new NumberTypeClass{Id = 0, NumberType = "Mobile"},
new NumberTypeClass{Id = 0, NumberType = "Work"},
new NumberTypeClass{Id = 0, NumberType = "Home"}
};
}

How to Deserialize datareader or data table to c# class

i have populated data reader from db table and i have class like
public class CandidateApplication
{
public string EmailID { get; set; }
public string Name { get; set; }
public string PhoneNo { get; set; }
public string CurrentLocation { get; set; }
public string PreferredWorkLocation { get; set; }
public int RoleApplingFor { get; set; }
public string CurrentJobTitle { get; set; }
public int EducationLevel { get; set; }
public decimal SalaryExpected { get; set; }
public string AvailableTime { get; set; }
public int AdvertID { get; set; }
public bool SignForAlert { get; set; }
public string CVInText { get; set; }
public string CVFileName { get; set; }
public bool IsDownloaded { get; set; }
public string specialization { get; set; }
public bool isallocated { get; set; }
public int id { get; set; }
public string AdvertAdditionalInfo { get; set; }
}
i can populate the above class in loop. we can iterate in data reader and populate class but i want to know is there any short cut way to populate class from data reader.
if data deserialization is possible from data reader to class then also tell me if few fields are there in class which are not there in data reader then how to handle the situation.
You don't need to use a Data Reader, You could just Populate the Data into a DataTable, and use the below method to create a List of your CandidateApplication Class.
The Call :-
List<CandidateApplication> CandidateList = GetCandidateInformation();
The Method that generates the list :-
public List<CandidateApplication> GetCandidateInformation()
{
DataTable dt = new DataTable();
using (OleDbConnection con = new OleDbConnection(ConfigurationManager.AppSettings["con"]))
{
using (OleDbCommand cmd = new OleDbCommand("SELECT * FROM [TableName]", con))
{
var adapter = new OleDbDataAdapter();
adapter.SelectCommand = cmd;
con.Open();
adapter.Fill(dt);
var CandApp = (from row in dt.AsEnumerable()
select new CandidateApplication
{
EmailID = row.Field<string>("EmailID"),
Name = row.Field<string>("Name"),
PhoneNo = row.Field<string>("PhoneNo"),
CurrentLocation = row.Field<string>("CurrentLocation"),
PreferredWorkLocation = row.Field<string>("PreferredWorkLocation"),
RoleApplingFor = row.Field<int>("RoleApplingFor"),
CurrentJobTitle = row.Field<string>("CurrentJobTitle"),
EducationLevel = row.Field<int>("EducationLevel "),
SalaryExpected = row.Field<decimal>("SalaryExpected"),
AvailableTime = row.Field<string>("AvailableTime"),
AdvertID = row.Field<int>("AdvertID"),
SignForAlert = row.Field<bool>("SignForAlert"),
CVInText = row.Field<string>("CVInText"),
CVFileName = row.Field<string>("CVFileName"),
IsDownloaded = row.Field<bool>("IsDownloaded"),
Specialization = row.Field<string>("Specialization"),
Isallocated = row.Field<bool>("Isallocated"),
Id = row.Field<int>("Id"),
AdvertAdditionalInfo = row.Field<string>("AdvertAdditionalInfo")
}).ToList();
return CandApp;
}
}
}
Although not an answer to your question, I would suggest you to consider the following workaround, which uses a SqlDataAdapter instead of a data reader:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Xml.Serialization;
class Program
{
static void Main(string[] args)
{
var cs = "YourConnectionString";
var xml = "";
using (var con = new SqlConnection(cs))
using (var c = new SqlCommand("SELECT * FROM CandidateApplication", con))
{
con.Open();
using (var adapter = new SqlDataAdapter(c))
{
var ds = new DataSet("CandidateApplications");
ds.Tables.Add("CandidateApplication");
adapter.Fill(ds, ds.Tables[0].TableName);
xml = ds.GetXml();
}
}
// We need to specify the root element
var rootAttribute = new XmlRootAttribute();
// The class to use as the XML root element (should match the name of
// the DataTable in the DataSet above)
rootAttribute.ElementName = "CandidateApplications";
// Initializes a new instance of the XmlSerializer class that can
// serialize objects of the specified type into XML documents, and
// deserialize an XML document into object of the specified type.
// It also specifies the class to use as the XML root element.
// I chose List<CandidateApplication> as the type because I find it
// easier to work with (but CandidateApplication[] will also work)
var xs = new XmlSerializer(typeof(List<CandidateApplication>), rootAttribute);
// Deserialize the XML document contained by the specified TextReader,
// in our case, a StringReader instance constructed with xml as a parameter.
List<CandidateApplication> results = xs.Deserialize(new StringReader(xml));
}
}
For those properties that are missing in the retrieved data, you could declare a private field with a default value:
string _advertAdditionalInfo = "default";
public string AdvertAdditionalInfo
{
get
{
return _advertAdditionalInfo;
}
set
{
_advertAdditionalInfo = value;
}
}
If you would like to enforce that the retrieved data will not fill in a specific property, use:
[XmlIgnoreAttribute]
public string AdvertAdditionalInfo { get; set; }
I made a generic function for converting the SELECT result from an OleDbCommand to a list of classes.
Let's say that I have a class that looks like this, which maps to the columns in the database:
internal class EconEstate
{
[Column(Name = "basemasterdata_id")]
public Guid BaseMasterDataId { get; set; }
[Column(Name = "basemasterdata_realestate")]
public Guid? BaseMasterDataRealEstate { get; set; }
[Column(Name = "business_area")]
public string BusinessArea { get; set; }
[Column(Name = "profit_centre")]
public int ProfitCentre { get; set; }
[Column(Name = "rentable_area")]
public decimal RentableArea { get; set; }
}
Then I can get a list of those EconEstate objects using this code:
public void Main()
{
var connectionString = "my connection string";
var objects = ReadObjects<EconEstate>(connectionString, "EMBLA.EconEstates").ToList();
}
private static IEnumerable<T> ReadObjects<T>(string connectionString, string tableName) where T : new()
{
using (var connection = new OleDbConnection(connectionString))
{
connection.Open();
using (var command = new OleDbCommand($"SELECT * FROM {tableName};", connection))
{
var adapter = new OleDbDataAdapter
{
SelectCommand = command
};
var dataTable = new DataTable();
adapter.Fill(dataTable);
foreach (DataRow row in dataTable.Rows)
{
var obj = new T();
foreach (var propertyInfo in typeof(T).GetProperties())
{
var columnAttribute = propertyInfo.GetCustomAttributes().OfType<ColumnAttribute>().First();
var value = row[columnAttribute.Name];
var convertedValue = ConvertValue(value, propertyInfo.PropertyType);
propertyInfo.SetValue(obj, convertedValue);
}
yield return obj;
}
}
}
}
private static object ConvertValue(object value, Type targetType)
{
if (value == null || value.GetType() == typeof(DBNull))
{
return null;
}
if (value.GetType() == targetType)
{
return value;
}
var underlyingTargetType = Nullable.GetUnderlyingType(targetType) ?? targetType;
if (value is string stringValue)
{
if (underlyingTargetType == typeof(int))
{
return int.Parse(stringValue);
}
else if (underlyingTargetType == typeof(decimal))
{
return decimal.Parse(stringValue);
}
}
var valueType = value.GetType();
var constructor = underlyingTargetType.GetConstructor(new[] { valueType });
var instance = constructor.Invoke(new object[] { value });
return instance;
}
As you can see, the code is generic, making it easy to handle different tables and classes.

Categories