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.
Related
I am using dotConnect for MySQL product of Devart. MySQL database structure likes this:
I am getting data like this:
public int user_id { get; set; } = 2;
public string lang { get; set; } = "en"; // Depending on the situation, it may also be "tr".
private readonly mainDataContext _db = new();
var cats = _db.categories.Where(s => s.u_id == user_id);
foreach (var cat in cats)
{
MessageBox.Show(cat.name_en);
}
In the MessageBox.Show I can not use cat.name + "_" + lang like PHP. I don't know how to get over this problem.
In nutshell, you can use this:
cat.GetType().GetProperty("name_" + lang).GetValue(cat,null))
But it's better to call a method to get value:
static public T getval<T>(Object obj, string field)
{
return (T)obj.GetType().GetProperty(field).GetValue(obj, null);
}
Here is a full example:
using System;
namespace Example
{
public class user
{
public int user_id { get; set; } = 2;
public string name_en { get; set; }
public string name_tr { get; set; }
}
class Program
{
static public T getval<T>(Object obj, string field)
{
return (T)obj.GetType().GetProperty(field).GetValue(obj, null);
}
static void Main(string[] args)
{
List<user> u = new List<user>();
u.Add(new user { user_id = 1, name_en = "Foods", name_tr = "name_tr value 1" });
u.Add(new user { user_id = 2, name_en = "Pizza", name_tr = "name_tr value 2" });
u.Add(new user { user_id = 2, name_en = "Other", name_tr = "name_tr vale 3" });
var lang = "en";
var cats = u.Where(s => s.user_id == 2);
foreach (var cat in cats)
{
Console.WriteLine(getval<string>(cat,"name_"+lang));
}
return;
}
}
}
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;
};
}
This question already has answers here:
Convert DataSet to List
(11 answers)
Closed 8 years ago.
I am using SqlHelper to execute the stored procedure in the DB.
In a namespace called constants i defined something like this
public class ShowInstitutes
{
public string InstituteName { get; set; }
public string InstituteCity { get; set; }
public int InstituteId { get; set; }
}
In the DAL layer I am trying to execute stored proc and get results in IList format
public IList<ShowInstitutes> ShowInstitutes(int instituteId)
{
return SqlHelper.ExecuteDataset(dBConnection, "usp_SPName");
}
I am getting the following error:
Cannot implicitly convert type 'System.Data.DataSet' to 'System.Collections.Generic.IList<>
You can converting your Dataset result to IList like this.
public IList<ShowInstitutes> ShowInstitutes(int instituteId)
{
var dataTable = SqlHelper.ExecuteDataset(dBConnection, "usp_SPName");
var SourceLists = new List<ShowInstitutes>();
for (var index = 0; index < dataTable.Rows.Count; index++)
{
SourceLists.Add(new ShowInstitutes
{
InstituteName = Convert.ToString(dataTable.Rows[index]["Columnname"], CultureInfo.InvariantCulture),
InstituteCity = Convert.ToString(dataTable.Rows[index]["Columnname"], CultureInfo.InvariantCulture),
InstituteId = Convert.ToInt32(dataTable.Rows[index]["Columnname"], CultureInfo.InvariantCulture)
});
}
return SourceLists;
}
public IList<ShowInstitutes> ShowInstitutes(int instituteId)
{
var d = SqlHelper.ExecuteDataset(dBConnection, "usp_SPName");
var myData = d.Tables[0].AsEnumerable().Select(data => new ShowInstitutes{
InstituteName = data.Field<string>("InstituteName "),
InstituteCity = data.Field<string >("InstituteCity "),
InstituteId = data.Field<int>("InstituteId ")
});
var list = myData.ToList();
return list;
}
public class info
{
public string counter
{
get; set;
}
public string age
{
get;
set;
}
public string id
{
get;
set;
}
public string marks
{
get;
set;
}
public string name
{
get;
set;
}
public List<info> getdata()
{
string c = "Data Source=bla ;bla ;bla";
SqlConnection con = new SqlConnection(c);
DataSet ds = SqlHelper.ExecuteDataset(con, CommandType.Text, "SELECT * from table1");
var list = (ds.Tables[0].AsEnumerable().Select(
df =>
new info
{
age = df[0].ToString(),
counter = df[1].ToString(),
id = df[3].ToString(),
name = df[4].ToString(),
marks = df[2].ToString()
})).ToList();
return list;
}
}
class Program
{
static void Main(string[] args)
{
info a =new info();
List<info> list1= a.getdata();
foreach (var info in list1)
{
Console.WriteLine(info.name+" "+info.age+" "+info.marks);
}
Console.Read();
}
}
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.
I am a fairly new C# programmer and am getting stuck on trying to convert FQL results into a custom class...for example, I am doing the following, but it seems like a lot of steps...I was just returning a datatable, but wanted the result to be strongly typed class collection. I'd appreciate any insights. I'm open to other ways of achieving similar results as well.
Thanks,
Chad
public class FacebookFriends
{
public string FriendID { get; set; }
public string FriendName { get; set; }
public string PicURLSquare { get; set; }
public string ProfileLink { get; set; }
//Gets your FB friends that are NOT currently using this application so you can invite them
public IEnumerable<FacebookFriends> GetFriendsNotUsingApp()
{
string strQuery = "SELECT uid, name, pic_square, link FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1=me()) AND NOT is_app_user";
FacebookSDKInterface objFQL = new FacebookSDKInterface();
dynamic objFNU = objFQL.FBFQL(strQuery);
//Construct the new, formated, merged datatable to store the results the way we want them
DataTable dtFriendsNotUsingApp = new DataTable();
dtFriendsNotUsingApp.Columns.Add("FriendID");
dtFriendsNotUsingApp.Columns.Add("FriendName");
dtFriendsNotUsingApp.Columns.Add("PicURLSquare");
dtFriendsNotUsingApp.Columns.Add("Link");
if (objFQL != null)
{
foreach (dynamic row in objFNU.data)
{
//Add New DataRow to new DataTable
DataRow drRow = dtFriendsNotUsingApp.NewRow();
//Get various values from original JSON Friend List returned
drRow["FriendID"] = row.uid;
drRow["FriendName"] = row.name;
drRow["PicURLSquare"] = row.pic_square;
drRow["Link"] = row.link;
//Add New Row to New Resulting Data Table
dtFriendsNotUsingApp.Rows.Add(drRow);
}
dtFriendsNotUsingApp.DefaultView.Sort = "FriendName";
}
IEnumerable<FacebookFriends> objFriendsListCollection = null;
var toLinq = from list in dtFriendsNotUsingApp.AsEnumerable()
select new FacebookFriends
{
FriendID = list["FriendID"].ToString(),
FriendName = list["FriendName"].ToString(),
PicURLSquare = list["PicURLSquare"].ToString(),
ProfileLink = list["ProfileLink"].ToString()
};
objFriendsListCollection = toLinq.OrderByDescending(p => p.FriendName);
return objFriendsListCollection;
} //Get FB Friends not already using this app
I belive this may help.
1st: I've never used the Facebook API, so I'm just using your code as an example.
2nd: As the method is inside the class, I've changed it to static. This way, you can use it by simply calling FacebookFriends.GetFriendsNotUsingApp(), instead of new FacebookFriends().GetFriendsNotUsingApp().
3rd The code:
public class FacebookFriends
{
public string FriendID { get; set; }
public string FriendName { get; set; }
public string PicURLSquare { get; set; }
public string ProfileLink { get; set; }
//Gets your FB friends that are NOT currently using this application so you can invite them
public static IEnumerable<FacebookFriends> GetFriendsNotUsingApp()
{
string strQuery = "SELECT uid, name, pic_square, link FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1=me()) AND NOT is_app_user";
FacebookSDKInterface objFQL = new FacebookSDKInterface();
dynamic objFNU = objFQL.FBFQL(strQuery);
List<FacebookFriends> friendsToReturn = new List<FacebookFriends>();
if (objFQL != null)
{
foreach (dynamic row in objFNU.data)
{
friendsToReturn.Add(new FacebookFriends()
{
FriendID = row.uid,
FriendName = row.name,
PicURLSquare = row.pic_square,
ProfileLink = row.link
}
);
}
}
return friendsToReturn;
} //Get FB Friends not already using this app
}
Hope this helps.
Regards
I have no experience with Facebook API or FQL as well, but by looking at your code objFNU.data appears to implement IEnumerable, hence you can use LINQ extension methods directly with it:
public class FacebookFriends
{
public string FriendID { get; set; }
public string FriendName { get; set; }
public string PicURLSquare { get; set; }
public string ProfileLink { get; set; }
//Gets your FB friends that are NOT currently using this application so you can invite them
public static IEnumerable<FacebookFriends> GetFriendsNotUsingApp()
{
string strQuery = "SELECT uid, name, pic_square, link FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1=me()) AND NOT is_app_user";
FacebookSDKInterface objFQL = new FacebookSDKInterface();
dynamic objFNU = objFQL.FBFQL(strQuery);
if (objFQL != null) // shouldn't you check objFNU for being null here instead?
{
IEnumerable<dynamic> objFNUdata = (IEnumerable<dynamic>)objFNU.data; // explicit cast might not be necessary
return objFNUdata.Select(row => new FacebookFriends()
{
FriendID = row.uid,
FriendName = row.name,
PicURLSquare = row.pic_square,
ProfileLink = row.link
}).OrderByDescending(p => p.FriendName);
}
else
{
return new List<FacebookFriends>();
}
} //Get FB Friends not already using this app
}
In the end, this worked best for me. Thanks to both, and especially #DarmirArh for all his help in getting this to work.
try
{
FacebookSDKInterface objFQL = new FacebookSDKInterface();
dynamic objFNU = objFQL.FBFQL(strQuery);
if (objFNU != null) // shouldn't you check objFNU for being null here instead?
{
IEnumerable<dynamic> objFNUdata = (IEnumerable<dynamic>)objFNU.data; // explicit cast might not be necessary
IEnumerable<FacebookFriends> objMyFriends =
from row in objFNUdata
select new FacebookFriends()
{
FriendID = row.uid,
FriendName = row.name,
PicURLSquare = row.pic_square,
ProfileLink = row.profile_url
};
objMyFriends = objMyFriends.OrderBy(p => p.FriendName);
return objMyFriends;
}
else
{
return new List<FacebookFriends>();
}
}
catch (Exception ex)
{
return new List<FacebookFriends>();
}