How to create a SQLite database UWP - c#

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);
}

Related

DataGridView taking more than usual to show records

I have a class product
class Product
{
public String Name { get; set; }
public byte[] Image { get; set; }
public Decimal Price { get; set; }
}
enter code here
and a functions to insert and retrieve data from sql database using Dapper.
public List<Product> GetProduct()
{
Connection conn = new Connection();
using (IDbConnection connection = new System.Data.SqlClient.SqlConnection(conn.connect.ConnectionString))
{
return connection.Query<Product>($"Select Name,Image,ComboPrice from Table_Products").ToList();
}
}
public void InsertProduct(String name, byte[] image, Decimal price)
{
Connection conn = new Connection();
using (IDbConnection connection = new System.Data.SqlClient.SqlConnection(conn.connect.ConnectionString))
{
List<Product> product = new List<Product>();
product.Add(new Product { Name = name, Image = image, ComboPrice = price });
connection.Execute("Insert into Table_Products(Name,Image,ComboPrice) values(#Name,#Image,#ComboPrice)", product);
}
}
This is how i am inserting record in database after parsing image into byte.
private void Insert_Click(object sender, EventArgs e)
{
byte[] photo;
using (var stream = File.OpenRead(txtPhoto.Text))
{
photo = new byte[stream.Length];
stream.Read(photo, 0, photo.Length);
}
db.InsertProduct(txt_description.Text,photo, Convert.ToDecimal(txt_price.Text));
}
I have tried two ways to set datasource in a datagridview.
A simple one:
dataGridView1.DataSource = db.GetProduct();
And using Async method:
public async void LoadProduct()
{
await Task.Run(() => dataGridView1.Invoke(new Action(() =>{dataGridView1.DataSource = db.GetProduct();})));
}
Issue
: Now The problem is sometimes even without Async method it pulls record and display all of them including images in less than a second. and very often it takes more than 10 seconds to display records with Async method and without Async too.
In short i don't know the issue is in my laptop or a code that i have written, also i want to know that have i written this code perfectly from performance perspective?

c# how to decide whether to add to sub-list or start new one

I have an sql query that provides me my data where I sometimes have lines that should be clustered (the data is aligned with an order by). The data is grouped by the field CAPName. Going through those rows line by line, I need to decide whether a new list should be initiated (content of CAPName differs to previous itteration), or whether the (already) initated list (from the previous iteration) should be added, too.
My pain lays with the location of the declaration of the relatedCapabilitySystem list.
I wanted to declare it within the if statement (Because, as I stated I need to decide whether the list from the previous iteration should be added too, or whether it should start a new list), but I can't as the compiler throws an exception, as the RLCapSys.Add(rCs); is non-existing in this content (which is only theoretically true). I understand why the compiler throws this exception. But if I declare the list on a "higher" level, than I always have a new list, which I don't want in the case that the item should be added to the list defined in the iteration(s) (1 or more) before
So what I want to achieve is, generate the list RLCapSys and add to it, in case the previous iteration contains the same CAPName (for clustering), otherwise create a new list.
SqlCommand cmdDetail = new SqlCommand(SQL_SubSytemsToCapability, DBConDetail);
SqlDataReader rdrDetail = cmdDetail.ExecuteReader();
List<relatedCapility> RLCaps = new List<relatedCapility>();
string lastCapShown = null;
while (rdrDetail.Read())
{
List<relatedCapabilitySystem> RLCapSys = new List<relatedCapabilitySystem>();
if (lastCapShown != rdrDetail["CAPName"].ToString())
{
//List<relatedCapabilitySystem> RLCapSys2 = new List<relatedCapabilitySystem>();
relatedCapility rC = new relatedCapility
{
Capability = rdrDetail["CAPName"].ToString(),
systemsRelated = RLCapSys,
};
RLCaps.Add(rC);
}
relatedCapabilitySystem rCs = new relatedCapabilitySystem
{
system = rdrDetail["name"].ToString(),
start = rdrDetail["SysStart"].ToString(),
end = rdrDetail["SysEnd"].ToString(),
};
RLCapSys.Add(rCs);
// method to compare the last related Capability shown create a new related Capabilty entry or add to the existing releated Capabilty related system list
lastCapShown = rdrDetail["CAPName"].ToString();
}
DBConDetail.Close();
and for reason of completness (but I think it is not needed here):
internal class CapabilitiesC
{
public List<Capability>Capabilities{ get;set;}
}
public class Capability
{
public string name { get; internal set; }
public string tower { get; internal set; }
public string color { get; internal set; }
public List<relatedCapility> related { get; set; }
}
public class relatedCapility
{
public string Capability { get; set; }
public List<relatedCapabilitySystem> systemsRelated { get; set; }
}
public class relatedCapabilitySystem
{
public string system { get; set; }
public string start { get; set; }
public string end { get; set; }
}
The purpose of your code is to take the input data and group it by capability. However, that is not immediately obvious. You can change your code to use LINQ so it becomes easier to understand and in the process solving your problem.
First you need a type to represent a record in your database. For lack of better name I will use Record:
class Record
{
public string System { get; set; }
public string Start { get; set; }
public string End { get; set; }
public string Capabilty { get; set; }
}
You can then create an iterator block to return all the records from the database (using an OR mapper like Entity Framework avoids most of this code and you can even shift some of the work from your computer to the database server):
IEnumerable<Record> GetRecords()
{
// Code to create connection and command (preferably in a using statement)
SqlDataReader rdrDetail = cmdDetail.ExecuteReader();
while (rdrDetail.Read())
{
yield return new Record {
System = rdrDetail["name"].ToString(),
Start = rdrDetail["SysStart"].ToString(),
End = rdrDetail["SysEnd"].ToString(),
Capability = rdrDetail["CAPName"].ToString()
};
}
// Close connection (proper using statement will do this)
}
Finally, you can use LINQ to perform the grouping:
var RLCaps = GetRecords()
.GroupBy(
record => record.Capability,
(capability, records) => new relatedCapility
{
Capability = capability ,
systemsRelated = records
.Select(record => new relatedCapabilitySystem
{
system = record.System,
start = record.Start,
end = record.End
})
.ToList()
})
.ToList();
Why not just assign it as NULL. The pattern would be
List<> myList = null;
if(condition)
{
myList = new List<>();
}
else
{
myList = previousList;
}
myList.Add();
previousList = myList;
I've got it working now. Thx everyone for your help. #martin, thx for your solution, you have put quite some effort into this, but that would have required for me to completely re-write my code. I am sure your approach would work and will be my next approach should I have a similar problem again.
It was a combination of the other answers that helped me figure it out. Let me show you what I ended up with:
SqlCommand cmdDetail = new SqlCommand(SQL_SubSytemsToCapability, DBConDetail);
SqlDataReader rdrDetail = cmdDetail.ExecuteReader();
List<relatedCapility> RLCaps = new List<relatedCapility>();
List<relatedCapabilitySystem> RLCapSys = new List<relatedCapabilitySystem>();
string lastCapShown = null;
while (rdrDetail.Read())
{
if (lastCapShown != rdrDetail["CAPName"].ToString())
{
RLCapSys = relatedCapabilitySystemList();
relatedCapility rC = new relatedCapility
{
Capability = rdrDetail["CAPName"].ToString(),
systemsRelated = RLCapSys,
};
RLCaps.Add(rC);
}
relatedCapabilitySystem rCs = new relatedCapabilitySystem
{
system = rdrDetail["name"].ToString(),
start = rdrDetail["SysStart"].ToString(),
end = rdrDetail["SysEnd"].ToString(),
};
RLCapSys.Add(rCs);
// method to compare the last related Capability shown create a new related Capabilty entry or add to the existing releated Capabilty related system list
lastCapShown = rdrDetail["CAPName"].ToString();
}
DBConDetail.Close();
So that's the section already shown bevor including my changes. Plus I added this:
private List<relatedCapabilitySystem> relatedCapabilitySystemList()
{
List<relatedCapabilitySystem> RLCapSys = new List<relatedCapabilitySystem>();
return RLCapSys;
}
Now I have new list reference everytime the CapName changes that is then added to the "higher" list. Before I had the issue of the very same list repeatedly assigned rather than a fresh one started. So thx again for your effort.

Adding items to a list with out overwriting the previous item

I am trying to send form data to a confirmation page where you would enter your cc info to complete the transaction. I add all the information to a list that i will later code as hidden fields on the new form to send the information off as paid. However when I do a repsonse.write to see what the information stored is. i always get the same name over and over. not exactly sure where i am missing it. Thanks for your help!
protected void Page_Load(object sender, EventArgs e)
{
if (Request.HttpMethod == "POST"){
formData attendee = new formData();
NameValueCollection nvc = Request.Form;
List<formData> attendees = new List<formData>();
if (!string.IsNullOrEmpty(nvc["fn1"]))
{
var fn = nvc["fn1"];
var ln = nvc["ln1"];
var email = nvc["email1"];
var wife = nvc["wife1"];
var luncheon = nvc["lucheon1"];
attendee.firstName = fn; attendee.lastName = ln; attendee.email = email; attendee.wife = wife; attendee.luncheon = luncheon;
attendees.Add(attendee);
}
if (!string.IsNullOrEmpty(nvc["fn2"]))
{
var fn = nvc["fn2"];
var ln = nvc["ln2"];
var email = nvc["email2"];
var wife = nvc["wife2"];
var luncheon = nvc["lucheon2"];
attendee.firstName = fn; attendee.lastName = ln; attendee.email = email; attendee.wife = wife; attendee.luncheon = luncheon;
attendees.Add(attendee);
}
foreach(var person in attendees)
{
Response.Write(person.firstName.ToString());
Response.Write(person.lastName.ToString());
Response.Write(person.email.ToString());
Response.Write(person.wife.ToString());
Response.Write(person.luncheon.ToString());
}
}
}
public class formData
{
public string firstName { get; set; }
public string lastName { get; set; }
public string email { get; set; }
public string wife { get; set; }
public string luncheon { get; set; }
}
}
I assume your array of Attendees is going to be of a data type like this... each attendee has a {fn, ln, email, wife, and luncheon} property. Looks like they're stored in the POST like {fn1, ln1, email1, wife1, luncheon1} is attendee(0), {fn2, ln2, email2, wife2, luncheon2} is attendee(1), etc.
You might try looping like this
var count = 1;
while (!string.IsNullOrEmpty(nvc["fn" + count]))
{
attendee(count).firstname=nvc["fn" + count]
attendee(count).lastname=nvc["ln" + count]
//...for the rest of the fields
count++; //be sure and increment count
}
Until there's data fn# that is null, it keeps looping through and creating attendees.
You are creating the list in the Page_Load event. The Page_Load event fires each time the page loads, postback or not and recreating the list every time that event fires.
You can create and use a session variable. As an example:
protected void Page_Load(object sender, EventArgs e)
{
List<formData> attendees;
if(Session["attendees"] == null)
{
attendees = new List<formData>();
// your logic logic ...
Session["attendees"] = attendees;
}
else
{
var attendees = (List<formData>)Session["attendees"];
// your logic ...
Session["attendees"] = attendees;
}
}
I'd also consider breaking your code out a bit. Perhaps putting the code that adds to the list in a separate method.
ASP.NET Session State Overview.

Adding list to list and reading from it?

I have a problem where I need to store a List in another Class/List.
I have this class:
public class InformationMyTravels
{
public string MyTravelsDate { get; set; }
public string MyTravelsFromLocation { get; set; }
public string MyTravelsToLocation { get; set; }
}
And I can populate a List and then save it to my isolated storage (AppSettings).
The problem is that when I have more than one "Overview" below, then the following code will just append the travel history.
What I need is a separation of "Overview", so that the List I populate for each Overview is saved in another Class/List, which can contain the x-number of "Overview" lists I fetch.
private async Task Fetch()
{
AppSettings localStorage = new AppSettings();
List<InformationMyTravels> mytravelsreturned = new List<InformationMyTravels>();
// I need to separate the returned data per Overview
foreach (Overview loaded in localStorage.OverviewSetting)
{
string mytravelsHtml = await WebRequests.LoadPageAsyncSpecificRKMyTravels(loaded.CardOverviewID);
HtmlDocument htmlDocumentmytravels = new HtmlDocument();
htmlDocumentmytravels.LoadHtml(mytravelsHtml);
foreach (HtmlNode table in htmlDocumentmytravels.DocumentNode.SelectNodes("//table[#class='table']"))
{
foreach (HtmlNode row in table.SelectNodes("tr"))
{
InformationMyTravels newTravel = new InformationMyTravels();
newTravel.MyTravelsDate = row.SelectSingleNode("td[1]").InnerText.Trim();
newTravel.MyTravelsFromLocation = row.SelectSingleNode("td[3]").InnerText.Trim();
newTravel.MyTravelsToLocation = row.SelectSingleNode("td[5]").InnerText.Trim();
// Here it just appends with newTravel's
mytravelsreturned.Add(newTravel);
}
}
mytravelsreturned.Reverse();
}
localStorage.MyTravelsSetting = mytravelsreturned;
}
So how do I take "mytravelsreturned" and add this to another Class/List?
And afterwards I need to select the specific listindex from the new class and load the travels into a listbox.ItemsSource
Wanted hierarchy:
Class/List
InformationMyTravels (0)
MyTravelsDate(0)
MyTravelsFromLocation (0)
MyTravelsToLocation(0)
MyTravelsDate(1)
MyTravelsFromLocation (1)
MyTravelsToLocation(1)
etc.
InformationMyTravels (1)
MyTravelsDate(0)
MyTravelsFromLocation (0)
MyTravelsToLocation(0)
MyTravelsDate(1)
MyTravelsFromLocation (1)
MyTravelsToLocation(1)
etc.
I then need to load e.g InformationMyTravels (1) into a listbox.ItemsSource
I hope it makes sense.
Below is the untested code(I am not on Windows currently). It should give you the Idea.
Class InformationMyTravelsList<T> : List<T>
{
public int id{get; private set;}
public void AddInfo(int ID, InformationMyTravels info)
{
this.id = ID;
this.Add(info);
}
}
Class Main
{
void myLogic()
{
InformationMyTravels info = new InformationMyTravels();
InformationMyTravelsList<InformationMyTravels> infoList = new InformationMyTravelsList<InformationMyTravels>();
infoList.AddInfo(info); //add as many you want
List<InformationMyTravelsList<InformationMyTravels>> myList = new InformationMyTravelsList<InformationMyTravels>>();
myList.Add(infoList);
myListBox.DataSource = myList;
}
}

How to cast from a list with objects into another list.

I have an Interface [BindControls] which takes data from GUI and store it into a list „ieis”.
After that, Into another class, which sends this data through WebServices, I want to take this data from „ieis” and put it into required by WS Class fields (bottom is a snippet of code)
This is the interface:
void BindControls(ValidationFrameBindModel<A.B> model)
{
model.Bind(this.mtbxTax, (obj, value) =>
{
var taxa = TConvertor.Convert<double>((string)value, -1);
if (taxa > 0)
{
var ieis = new List<X>();
var iei = new X
{
service = new ServiceInfo
{
id = Constants.SERVICE_TAX
},
amount = tax,
currency = new CurrencyInfo
{
id = Constants.DEFAULT_CURRENCY_ID
}
};
ieis.Add(iei);
}
},"Tax");
}
This is the intermediate property:
//**********
class A
{
public B BasicInfo
{
get;
set;
}
class B
{
public X Tax
{
get;
set;
}
}
}
//***********
This is the class which sends through WS:
void WebServiceExecute(SomeType someParam)
{
//into ‚iai’ i store the data which comes from interface
var iai = base.Params.FetchOrDefault<A>( INFO, null);
var convertedObj = new IWEI();
//...
var lx = new List<X>();
//1st WAY: I tried to put all data from ‚Tax’into my local list ‚lx’
//lx.Add(iai.BasicInfo.Tax); - this way is not working
//2nd WAY: I tried to put data separately into ‚lx’
var iei = new X
{
service = new ServiceInfo
{
id = iai.BasicInfo.Tax.service.id
},
amount = iai.BasicInfo.Tax.amount,
currency = new CurrencyInfo
{
id = iai.BasicInfo.Tax.currency.id
}
};
lx.Add(iei);
// but also is not working
Can you help me please to suggest how to implement a way that will fine do the work (take data from ‚ieis’ and put her into ‚lx’).
Thank you so much
As noted in my comment, it looks like iai.BasicInfo.Tax is null, once you find out why that is null your original Add() (#1) will work.

Categories

Resources