Having a convertion issue between my WCF service returned ObservableCollection and handling the result to fill a ListView.
So in both WCF and PCL Projects i have this Temoignage.cs in Model folder
public class Temoignage
{
public string Nom { get; set; }
public string Prenom { get; set; }
public int Note { get; set; }
public string Texte { get; set; }
}
The WCF service returning this
public ObservableCollection<Temoignage> GetTemoignage()
{
ObservableCollection<Temoignage> TemoignageList = new ObservableCollection<Temoignage>();
con.Open();
SqlCommand cmd = new SqlCommand("Select U.nom, U.Prenom, T.note, T.texte from dbo.Temoignages T inner join Users U on U.id = T.iduser where T.validation = 1;", con);
SqlDataReader reader = cmd.ExecuteReader();
if (reader.HasRows)
while (reader.Read())
{
Temoignage temoignage = new Temoignage
{
Nom = reader.GetString(0),
Prenom = reader.GetString(1),
Note = reader.GetInt32(2),
Texte = reader.GetString(3)
};
TemoignageList.Add(temoignage);
}
return TemoignageList;
}
And the ViewModel which receive it
public ObservableCollection<Temoignage> TemoignagesList { get; set; }
....
public void Temoignages()
{
BasicHttpBinding binding = CreateBasicHttp();
this.client1 = new BienEtreServiceClient(binding, EndPoint);
this.instance = ((IBienEtreService)client1.InnerChannel);
client1.GetTemoignageCompleted += ClientOnGetTemoignageCompleted;
client1.GetTemoignageAsync();
}
public void ClientOnGetTemoignageCompleted(object sender, GetTemoignageCompletedEventArgs e)
{ // The problems starts here
ObservableCollection<Temoignage> TemTest = e.Result;
foreach (Temoignage item in TemTest)
{
TemoignagesList.Add(item);
}
}
I thought i could, in ClientOnGetTemoignageCompleted, just take the ObservableCollection i got from WCF and add the elements in my already existing TemoignagesList (which is binded to XAML).
But nope. Even if the Models contains same elements in both projects.
e.Result containt elements i need, i just don't know how to read them.
equals to this when ClientOnGetTemoignageCompleted is executed
Am i missing an important point?
Thanks for help
I think i found it myself, using the models of my wcf service and not the client ones
//using BienEtre.Models;
using BienEtreWcfService;
Now this works and add elements to the list.
public void ClientOnGetTemoignageCompleted(object sender, GetTemoignageCompletedEventArgs e)
{
foreach (Temoignage item in e.Result)
{
TemoignagesList.Add(item);
}
}
Not sure i understood, but it works!
I'm also using List instead of ObservableCollection.
Related
I have experience in working and fixing bugs with existing code bases that implement MySql code, but have to design a new program from scratch at my new job. I am not sure what is the best way to return data from MySqlDataReader to my custom models. Please advise!
Here's what I have,
Folder structure:
Models (folder)
Metadata.cs
User.cs
MySqlDb.cs
Metadata.cs: Reresents data from metadata table
public class Metadata
{
public int Id { get; set; }
public string Title { get; set; }
public string Sku { get; set; }
public bool IsLive { get; set; }
}
User.cs: Represents data from user table
public class User
{
public int Id { get; set; }
public string UserName { get; set; }
public int Age { get; set; }
public string Address { get; set; }
}
MySqlDb.cs
using MySql.Data;
using MySql.Data.MySqlClient;
public class MySqlDb
{
public MySqlConnection Connection { get; set;}
public MySqlDb(string connectionString)
{
Connection = new MySqlConnection(connectionString);
}
public List<Metadata> RunSelectQueryForMetadata(string query)
{
var rdr = new MySqlCommand(query, Connection).ExecuteReader();
var metadata = new List<Metadata>();
using (rdr)
{
while(rdr.Read())
{
metadata.Add(
new Metadata {
Id = rdr["id"],
Title = rdr["title"],
Sku = rdr["sku"],
IsLive = rdr["islive"],
});
} // while
} // using
return metadata;
} // public void RunSelectQuery(string query)
} // public class MySqlDb
If I try to get Users data, I am thinking of writing another method (RunSelectQueryForUsers). I would like to avoid writing different methods for different tables. I am not sure how to use one method for retrieving data from different tables with different data structures and typecast them to the Model I want.
Any help is greatly appreciated!!
One way is to use micro-orm such as Dapper which is a simple object mapper built for .Net. Dapper extends the IDbConnection by providing useful extension methods to query your database.
Example of implementing dapper within your current menthod:
public List<Metadata> RunSelectQueryForMetadata(string query)
{
var metadata = new List<Metadata>();
try // implement proper error handling
{
Connection.Open();
metadata = Connection.Query<Metadata>(query).ToList();
Connection.Close();
}
catch(Exception ex)
{
// error here
}
return metadata;
}
Some useful links:
Dapper Github
Dapper Tutorial
Converting it to generic method: (not tested right now)
public List<T> RunSelectQuery<T>(string query)
{
try // implement proper error handling
{
Connection.Open();
metadata = Connection.Query<T>(query).ToList();
Connection.Close();
}
catch(Exception ex)
{
// error here
}
return metadata;
}
and use something like this below:
List<Metadata> myMetadata = RunSelectQuery<Metadata>(query);
I prefer a pattern more like this:
public class MySqlDb
{
//1. This should not be public!
// Keeping it private forces other code to go through your public methods,
// rather than using the connection directly.
// Even better if the class knows how to read the string from a
// config rile rather than accepting it via the constructor.
//2. Don't save a connection object for re-use.
// ADO.Net has a connection pooling feature that works when you
// create new objects for most queries
private string ConnectionString { get; set;}
public MySqlDb(string connectionString)
{
ConnectionString = connectionString;
}
//1. Use IEnumerable instead of List
// ...don't pull all of the results into memory at the same time until/unless you really have to.
//2. Methods that accept query strings should also accept parameters.
// Otherwise you are forced to build sql strings in insecure crazy-vulnerable ways
public IEnumerable<Metadata> RunSelectQueryForMetadata(string query, IEnumerable<MySqlParameter> parameters)
{
using (var cn = new MySqlConnection(ConnectionString))
using (var cmd = new MySqlCommand(query, cn))
{
if (parameters != null)
{
cmd.Parameters.AddRange(parameters.ToArray());
}
cn.Open();
using(var rdr = cmd.ExecuteReader())
{
while(rdr.Read())
{
yield return new Metadata {
Id = rdr["id"],
Title = rdr["title"],
Sku = rdr["sku"],
IsLive = rdr["islive"],
};
}
rdr.Close();
}
}
}
}
Ultimately, the ideal is for the RunSelectQuery__() method to be generic and private, and for public methods to not accept SQL statements. The goal is to force all SQL in your program to live in the MySqlDb class. Each query has a method that accepts specific typed inputs, and returns typed output. The reason you have that goal is to make it easy to manage your database access and easy to audit that all of your SQL code is safely using parameters (and not vulnerable to sql injection attacks! ). You want something like this:
//updated to remove the earlier explanatory comments
// and show example methods for isolating SQL from the rest of the application.
public class MySqlDb
{
private string ConnectionString { get; set;}
private string ReadConnectionStringFromConfigFile()
{
//TODO
throw NotImplementedException();
}
public MySqlDb()
{
ConnectionString = ReadConnectionStringFromConfigFile();
}
//This is now PRIVATE and generic, and allows for parameterized queries
private IEnumerable<T> RunSelectQuery(string query, Func<IDataReader, T> translateRecord, IEnumerable<MySqlParameter> parameters)
{
using (var cn = new MySqlConnection(ConnectionString))
using (var cmd = new MySqlCommand(query, cn))
{
if (parameters != null)
{
cmd.Parameters.AddRange(parameters.ToArray());
}
cn.Open();
using(var rdr = cmd.ExecuteReader())
{
while(rdr.Read())
{
yield return translateRecord(rdr);
}
rdr.Close();
}
}
}
////// Example methods showing how to use the generic method above
// These methods are the only public part of your class
public MetaData GetMetaDataById(int ID)
{
string sql = "SELECT * FROM MetatData WHERE ID= #ID";
var parameters = new List<MySqlParameters> {
new MySqlParameter() {
ParameterName = "#ID",
MySqlDbType = MySqlDbType.Int32,
Value = ID
}
};
return RunSelectQuery<MetaData>(sql, parameters, r =>
new Metadata {
Id = r["id"],
Title = r["title"],
Sku = r["sku"],
IsLive = r["islive"],
}).FirstOrDefault();
}
public IEnumerable<MetaData> GetAllMetaData()
{
string sql = "SELECT * FROM MetatData";
return RunSelectQuery<MetaData>(sql, null, r =>
new Metadata {
Id = r["id"],
Title = r["title"],
Sku = r["sku"],
IsLive = r["islive"],
});
}
public User GetUserByID(int ID)
{
string sql = "SELECT * FROM User WHERE ID= #ID";
var parameters = new List<MySqlParameters> {
new MySqlParameter() {
ParameterName = "#ID",
MySqlDbType = MySqlDbType.Int32,
Value = ID
}
};
return RunSelectQuery<User>(sql, parameters, r =>
new Metadata {
Id = r["id"],
UserName = r["UserName"],
Age = r["Age"],
Address = r["Address"],
}).FirstOrDefault();
}
public User GetUserByUsername(string UserName)
{
string sql = "SELECT * FROM User WHERE Username= #UserName";
var parameters = new List<MySqlParameters> {
new MySqlParameter() {
ParameterName = "#UserName",
MySqlDbType = MySqlDbType.VarChar,
Size = 20, //guessing at username lenght
Value = UserName
}
};
return RunSelectQuery<User>(sql, parameters, r =>
new Metadata {
Id = r["id"],
UserName = r["UserName"],
Age = r["Age"],
Address = r["Address"],
}).FirstOrDefault();
}
public IEnumerable<User> FindUsersByAge(int Age)
{
string sql = "SELECT * FROM User WHERE Age = #Age";
var parameters = new List<MySqlParameters> {
new MySqlParameter() {
ParameterName = "#Age",
MySqlDbType = MySqlDbType.Int32,
Value = Age
}
};
return RunSelectQuery<User>(sql, parameters, r =>
new Metadata {
Id = r["id"],
UserName = r["UserName"],
Age = r["Age"],
Address = r["Address"],
});
}
}
In larger applications, you abstract this further into a separate project, with a private class for the lower-level methods that are private here, and a public class for each of the object types you use via that database. You might even go full-blown service-oriented architecture, where you get all your data via web service calls, and only the service layer talks directly to any database.
Of course, at this level you can also use a mirco-ORM like Dapper. Micro-ORMs will help you avoid re-writing the same mapping code over and over, and also help more with the INSERT/UPDATE side of data operations. Their goal is to take over as much of the boilerplate code for you as they can.
The advantage of a micro-ORM over a full ORM is it keeps you closer to the SQL. This is a good thing. Full-blown ORMs like Entity Framework or NHibernate effectively force you to learn a whole new language on top of the SQL, while mostly limiting you to basic SQL statements that often lose the advantages from the "relational" part of a relational database. Eventually, you often end up needing to understand and write complex raw SQL anyway to optimize performace. Micro-ORMs try to offer a happy-medium... taking away as much of the boiler plate code needed to talk to a database as they can, while still leaving you to write your own SQL.
While not tailored to using MySql and straight up sql, the below code snippets provide a means to do what you're asking using generics. Could use some improvements though...
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Data.General
{
public abstract class DataObject
{
protected abstract void Initialize(IDataRecord dataRow);
private static string _connectionString = "";
/// <summary>
/// Loads a single data object from the results of a stored procedure.
/// </summary>
protected static T ReadObject<T>(string procedureName, SqlParameter[] sqlParameters, Type dataType)
{
DataObject returnItem = null;
using (SqlConnection sqlConnection = new SqlConnection(GetConnectionString()))
using (SqlCommand command = BuildCommand(sqlConnection, procedureName, sqlParameters))
{
sqlConnection.Open();
//Execute the reader for the given stored proc and sql parameters
using (IDataReader reader = command.ExecuteReader())
{
//If we get no records back we'll still return null
while (reader.Read())
{
returnItem = (DataObject)Activator.CreateInstance(typeof(T));
returnItem.Initialize(reader);
break;
}
}
}
//Return our DataObject
return (T)Convert.ChangeType(returnItem, dataType);
}
/// <summary>
/// Reads a collection of data objects from a stored procedure.
/// </summary>
protected static List<T> ReadObjects<T>(string procedureName, SqlParameter[] sqlParameters)
{
//Get cached data if it exists
List<T> returnItems = new List<T>();
T dataObject;
using (SqlConnection sqlConnection = new SqlConnection(GetConnectionString()))
using (SqlCommand command = BuildCommand(sqlConnection, procedureName, sqlParameters, null))
{
sqlConnection.Open();
//Execute the reader for the given stored proc and sql parameters
using (IDataReader reader = command.ExecuteReader())
{
//If we get no records back we'll still return null
while (reader.Read())
{
dataObject = (T)Activator.CreateInstance(typeof(T));
(dataObject as DataObject).Initialize(reader);
returnItems.Add(dataObject);
}
}
}
//Return the DataObjects
return returnItems;
}
/// <summary>
/// Builds a SQL Command object that can be used to execute the given stored procedure.
/// </summary>
private static SqlCommand BuildCommand(SqlConnection sqlConnection, string procedureName, SqlParameter[] sqlParameters, SqlTransaction sqlTransaction = null)
{
SqlParameter param;
SqlCommand cmd = new SqlCommand(procedureName, sqlConnection);
if (sqlTransaction != null)
{
cmd.Transaction = sqlTransaction;
}
cmd.CommandType = CommandType.StoredProcedure;
// Add SQL Parameters (if any)
foreach (SqlParameter parameter in sqlParameters)
{
param = new SqlParameter(parameter.ParameterName, parameter.DbType);
param.Value = parameter.Value;
cmd.Parameters.Add(param);
}
return cmd;
}
private static string GetConnectionString()
{
return _connectionString;
}
public static void SetConnectionString(string connectionString)
{
_connectionString = connectionString;
}
}
}
namespace Data.Library
{
public class Metadata : General.DataObject
{
protected Data.Model.Metadata _metaData;
public Data.Model.Metadata BaseModel
{
get { return _metaData; }
set { _metaData = value; }
}
//Typically I have properties in here pointing to the Data.Model class
protected override void Initialize(System.Data.IDataRecord dataRow)
{
_metaData = new Model.Metadata();
_metaData.Id = Convert.ToInt32(dataRow["Id"].ToString());
_metaData.Title = (dataRow["Title"].ToString());
_metaData.Sku = (dataRow["Sku"].ToString());
_metaData.IsLive = Convert.ToBoolean(dataRow["IsLive"].ToString());
}
public static Metadata ReadByID(int id)
{
return General.DataObject.ReadObject<Metadata>("dbo.s_MetadataGet", new[] { new SqlParameter("#ID", id) },
typeof(Metadata));
}
public static Metadata[] ReadBySku(string sku)
{
List<Metadata> metaDatas = General.DataObject.ReadObjects<Metadata>("dbo.s_MetadataGetBySku", new[] { new SqlParameter("#Sku", sku) });
return metaDatas.ToArray();
}
}
}
namespace Data.Model
{
public class Metadata
{
public int Id { get; set; }
public string Title { get; set; }
public string Sku { get; set; }
public bool IsLive { get; set; }
}
}
Trying to make a WCF Webservice for my xamarin forms app. It should just retreive text from sqlserver and fill a label with it.
The wcf method return a List of OfflineContent objects, as there may be more than one result for the sql request.
But when I try to call the method from client, I have this:
Cannot implicitly convert type 'void' to
'System.Collections.Generic.List'
I think i missed something but can't figured out what.
Here is project structure and code.
IBienEtreService.cs
[ServiceContract]
public interface IBienEtreService
{
[OperationContract]
List<OfflineContent> GetDataContent(string title);
}
[DataContract]
public class OfflineContent
{
[DataMember]
public string Title { get; set; }
[DataMember]
public string Text { get; set; }
[DataMember]
public string Picture { get; set; }
}
BienEtreService.svc
public List<OfflineContent> GetDataContent(string title)
{
List<OfflineContent> ContentList = new List<OfflineContent>();
con.Open();
SqlCommand cmd = new SqlCommand("select * from dbo.Content where title = #title", con);
cmd.Parameters.AddWithValue("#title", title);
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
OfflineContent content = new OfflineContent
{
Title = reader.GetString(1),
Text = reader.GetString(2)
};
ContentList.Add(content);
}
return ContentList;
}
At this point ContentList contain what I need.
The issue comes here in Lef_methode.xaml.cs
public partial class Left_Methode : ContentPage
{
static BienEtreServiceClient client1 = new BienEtreServiceClient();
public Left_Methode ()
{
InitializeComponent ();
//This fails
List<Content> list = client1.GetDataContentAsync("methode");
Mthd_txt.Text = "It's the label, should contain something like list[1].texte";
}
}
I seen the return type of GetDataContentAsync (I have to use the Async? I can't call the method directly without suffixes) is void in Reference.cs, which is generated automatically... And i need a List<OfflineContent> return type.
Can someone show me the right way please? The struggle is real i come back to dev after a long break.
I'm new in creating Data Bases and I should to create a SQLite DB, which contains Buses, every Bus contains a list of Stops and every Stop contains a timetable. I have create a class Buses:
class Buses
{
[PrimaryKey, AutoIncrement]
public string number { get; set; }
public List<Stop> stops = new List<Stop>();
}
public class Stop
{
public string StopName { get; set; }
public string Timetable { get; set; }
}
And I don't know how should I add stops to the DB. I trying something like this:
private void Add_Click(object sender, RoutedEventArgs e)
{
var s = conn.Insert(new Buses()
{
number = Id.Text,
stops = stops.Add(new Stop { StopName = StopName.Text, Timetable = Time.Text });
}
But I get error
The name 'stops' does not exist in the current context
I understand, why there such error is, but I don't know, how to fix it. It is possible, that there are easiest ways to adding such constructions to the DB.
I'm new in creating Data Bases and I should to create a SQLite DB, which contains Buses, every Bus contains a list of Stops and every Stop contains a timetable.
You cannot create a table with a column to store a list of object in SQLite. Because there is no such datatype supported in SQLite. So the Buses table you have created will never store its stop list into SQLite.
Based on my understanding, a bus can have many stops, and a stop is also used for many buses, the relationship between bus and stop should be Many-to-Many. So you may need to create another relationship table in addition to table Buses and table Stop. As both table Buses and table Stop are very simple in your scenario, I just create one relationship table here (it makes it simpler and also works but may cause redundancy):
class Buses
{
public string number { get; set; }
public string StopName { get; set; }
public string Timetable { get; set; }
}
Use the following code to add the stop:
private async void btnAddStop_Click(object sender, RoutedEventArgs e)
{
// check if the stop is already added for the bus
List<Buses> buses = new List<Buses>();
buses = LocalDatabase.GetStopListByBusNumberAndStopName(Id.Text, StopName.Text);
if (buses.ToArray().Length > 0)
{
await new MessageDialog("Cannot add this stop because the stop is already added for the bus!").ShowAsync();
}
else
{
Buses b = new Buses();
b.number = Id.Text;
b.StopName = StopName.Text;
b.Timetable = Timetable.Text;
// add the stop to db
LocalDatabase.InsertStopToDatabase(b);
await new MessageDialog("The stop is added successfully!").ShowAsync();
}
}
// get the buses by bus number
public static List<Buses> GetStopListByBusNumber(string busNumber)
{
List<Buses> results = new List<Buses>();
using (SQLite.Net.SQLiteConnection conn = new SQLite.Net.SQLiteConnection(new SQLite.Net.Platform.WinRT.SQLitePlatformWinRT(), DBPath))
{
results = conn.Query<Buses>("SELECT * FROM Buses WHERE number = ?", busNumber);
}
return results;
}
// get the buses by bus number and stop name
public static List<Buses> GetStopListByBusNumberAndStopName(string busNumber, string stopName)
{
List<Buses> results = new List<Buses>();
using (SQLite.Net.SQLiteConnection conn = new SQLite.Net.SQLiteConnection(new SQLite.Net.Platform.WinRT.SQLitePlatformWinRT(), DBPath))
{
results = conn.Query<Buses>("SELECT * FROM Buses WHERE number = ? AND StopName = ?", busNumber, stopName);
}
return results;
}
Then use the following code to retrieve the stop list for a bus:
// get the buses by bus number
public static List<Buses> GetStopListByBusNumber(string busNumber)
{
List<Buses> results = new List<Buses>();
using (SQLite.Net.SQLiteConnection conn = new SQLite.Net.SQLiteConnection(new SQLite.Net.Platform.WinRT.SQLitePlatformWinRT(), DBPath))
{
results = conn.Query<Buses>("SELECT * FROM Buses WHERE number = ?", busNumber);
}
return results;
}
Here is the entire sample for your reference.
The problem is the way fast object initializes work in .Net
var s = conn.Insert(new Buses()
{
number = Id.Text,
stops = stops.Add(new Stop { StopName = StopName.Text, Timetable = Time.Text });
}
Inside the initialize block - You cannot get the values your other members.
(Even if you could get the member value, the function stops.Add is void - which does not return a new list)
If you want to use the quick initialize way:
var s = conn.Insert(new Buses()
{
number = Id.Text,
stops = new List<Stop>()
{
new Stop { StopName = StopName.Text, Timetable = Time.Text }),
}
}
Or you can do it without:
private void Add_Click(object sender, RoutedEventArgs e)
{
var bus = new Buses()
{
number = Id.Text,
};
bas.stops.Add(new Stop { StopName = StopName.Text, Timetable = Time.Text });
var s = conn.Insert(bus);
}
I have stored the result of a stored procedure (in Entity Framework) in an IList and then bind my grid with this IList. When this result is null the grid hasn't got any columns but I need to show these columns in the grid. Is there any way to solve this problem?
This is my code:
IList list = new ArrayList();
try
{
var context = new SabzNegar01Entities1();
list = (from p in context.tbl_ReturnSalesFactor_D
let add = (p.MainNum * p.Fee)
let pureAdd = ((p.MainNum * p.Fee) - (p.MainNum * p.Discount)) + ((p.Tax + p.Charges) * p.MainNum)
let taxChange = (p.Tax + p.Charges) * p.MainNum
let discount = p.Discount * p.MainNum
where p.DocNo == inDocNo
select new { p.Row, p.StockCode, p.tbl_Stock.PDescription, p.Fee, p.MainNum, add, taxChange, discount, pureAdd }).ToList();
}
catch (Exception ex)
{
PMessageBox.Show(ex.Message, "Error in Reading ReturnSalesFactor_Details Data");
}
and binding:
radGridView_Product.DataSource = list ;
I would do this:
define a C# class that matches the data that you're getting back from the stored procedure (e.g. SalesInfo or whatever you want to call it)
then define your IList to be a List<SalesInfo> (please don't use the crappy old ArrayList anymore!)
when you call the stored procedure, but you get no values back, you just add a dummy SalesInfo entry to your list being returned, that e.g. has no data found as its description and everything else is empty/0.0
That way, your method will always return at least one element, and since that element is there, the gridview know it's columns and what to call them
Update:
I would first define a class to hold all those properties you want to display in your gridview:
// just a data container to hold the information - call it whatever you like!
// also: with the datatypes, I am just *GUESSING* because you didn't exactly tell us
// what those values are - adapt as needed !
public class SalesInfo
{
public int Row { get; set; }
public string StockCode { get; set; }
public string Description { get; set; }
public decimal Fee { get; set; }
public decimal MainNum { get; set; }
public decimal Add { get; set; }
public decimal TaxChange { get; set; }
public decimal Discount { get; set; }
public decimal PureAdd { get; set; }
}
Next, define a method that goes and gets that data from the stored procedure - if not data is returned, add a dummy entry instead:
// Define a method to return an IList of that data container class defined above
public IList<SalesInfo> GetSalesInfo()
{
// please, as of .NET 2.0 - use the List<T> and stop using ArrayList!
IList<SalesInfo> list = new List<SalesInfo>();
try
{
// put your context usage into using()..... blocks to ensure proper disposal
using (var context = new SabzNegar01Entities1())
{
// fetch the data, turn it into SalesInfo records
list = (from p in context.tbl_ReturnSalesFactor_D
where p.DocNo == inDocNo
select new SalesInfo
{
Row = p.Row,
StockCode = p.StockCode,
Description = p.tbl_Stock.PDescription,
Fee = p.Fee,
MainNum = p.MainNum,
Add = p.MainNum*p.Fee,
PureAdd = ((p.MainNum*p.Fee) - (p.MainNum*p.Discount)) + ((p.Tax + p.Charges)*p.MainNum),
Discount = p.Discount*p.MainNum,
TaxChange = (p.Tax + p.Charges)*p.MainNum
}).ToList();
}
// if you get back no data -> add a dummy entry
if (list.Count <= 0)
{
list.Add(new SalesInfo { Description = "(no data found)" });
}
}
catch (Exception ex)
{
PMessageBox.Show(ex.Message, "Error in Reading ReturnSalesFactor_Details Data");
}
// return the resulting list
return list;
}
I am having quite a lot of trouble trying to find a tutorial that will tech me how to use MySqlReader (with MySQL) to insert or receive data through a class object. The construtor is shown as follow.
Where I have used http://json2csharp.com/ to create these class I know how to serialize/deserialize a class object into JSON. my problem really lies in getting the data from a lot of different table in and out of the database connector via MySqlDataReader into a class object.
I don't know if this matter but I am using .Net 2.0 with C# 3.0 (visual studio 2010). Thank you in advance for any comment or reply.
public class Boardingzone
{
public string zone { get; set; }
public string time { get; set; }
}
public class Serial
{
public string rsn { get; set; }
public List<Boardingzone> boardingzone { get; set; }
}
public class RootObject
{
public string name { get; set; }
public List<Serial> serial { get; set; }
}
This is what i have tried so far
string sql = "SELECT Route.RName, RouteSerial.RSN, Stop.StopName, TimeTable.BoardTime FROM TimeTable INNER JOIN Stop ON TimeTable.StopID = Stop.StopID INNER JOIN RouteSerial ON TimeTable.RSN = RouteSerial.RSN INNER JOIN Route ON RouteSerial.RID = Route.RID";
MySqlCommand cmd = new MySqlCommand(sql, conn);
MySqlDataReader rdr = cmd.ExecuteReader();
ArrayList name = new ArrayList();
ArrayList rsn = new ArrayList();
ArrayList zone = new ArrayList();
ArrayList time = new ArrayList();
while (rdr.Read()){
string val = "";
val = rdr.GetValue(0).ToString();
name.Add(val);
val = rdr.GetValue(1).ToString();
rsn.Add(val);
val = rdr.GetValue(2).ToString();
zone.Add(val);
val = rdr.GetValue(3).ToString();
time.Add(val);
}
rdr.Close();
conn.Close();
you are almost doing it right. without going into too much detail, you need to instantiate the classes you want to populate:
var currentRoot = null;
var rootObjects = new List<RootObject>();
while (rdr.Read()){
string name= rdr.GetValue(0).ToString();
string serial = rdr.GetValue(1).ToString();
string bz = rdr.GetValue(2).ToString(); <-- made this up
if( currentRoot == null || currentRoot.name != name )
{
if( currentRoot != null ){
rootObjects.Add(currentRoot);
}
currentRoot = new RootObject();
currentRoot.name = name;
}
currentRoot.serials.Add(new Serial(){zone = bz});
... instantiate other classes
}
rdr.Close();
foreach( var rootObj in rootObjects) doSomethingWithRootObj(rootObj);
hope it helps.
I am not sure what the purpose of populating the ArrayList is, you will have to somehow populate your Model from your arraylist either by mapping or manually.
For the simple case why can you not just populate your model here?
One good approach to this would be to keep your Model in a separate assembly, your DAL can then reference this assembly in order to populate the appropriate classes.
Better still would be if you could expose your model as interfaces then the DAL need only use those interfaces and can have its own implementation - not sure if this is possible with the serialization method you use.