Retrieve Parent / Child Query result SQL Server with c# - c#

what I am doing here now is the probably the worst way of fulfilling my requirements but I haven't found any other way.
here is my sample database structure;
Here is the script that I use in order to retrieve the certain values;
SELECT DISTINCT h.HotelID, h.HotelName, r.RoomCode, r.RoomName, r.RoomID
FROM RoomsInHotel rh
INNER JOIN Hotels h ON rh.HotelID = h.HotelID
INNER JOIN Rooms r ON rh.RoomID = r.RoomID
order by h.HotelName, r.RoomCode;
Here is the result that the above script is giving me back;
everything is fine till here.
I need to move to C# code from here. What I would like to achieve is the following result;
Here is where I am worried about. I use Linq to achieve this thing and the below code is the code that I used for the above console result.
public class Hotel {
public int HotelID {get; set; }
public string HotelName {get; set; }
public IQueryable<Room> Rooms {get; set; }
}
public class HotelWithOneRoom {
public int HotelID { get; set; }
public string HotelName { get; set; }
public Room Room { get; set; }
}
public class Room {
public int RoomID {get; set; }
public string RoomCode {get; set; }
public string RoomName { get; set; }
}
class Program {
static void Main(string[] args) {
#region _assets
IList<HotelWithOneRoom> tempHotelWithOneRoom = new List<HotelWithOneRoom>();
IList<Hotel> tempDistinctHotels = new List<Hotel>();
IList<Room> tempRooms = new List<Room>();
#endregion
#region _connectionString
var connectionString = "Data Source=TOSHIBA-PC\\SQLEXPRESS;Initial Catalog=tbAccomm;Integrated Security=True";
#endregion
using (SqlConnection conn = new SqlConnection(connectionString)) {
using(SqlCommand cmd = conn.CreateCommand()) {
#region _connect to db, generate script and retrieve values
cmd.CommandText = "SELECT DISTINCT h.HotelID, h.HotelName, r.RoomCode, r.RoomName, r.RoomID FROM RoomsInHotel rh INNER JOIN Hotels h ON rh.HotelID = h.HotelID INNER JOIN Rooms r ON rh.RoomID = r.RoomID order by h.HotelName, r.RoomCode;";
cmd.CommandType = System.Data.CommandType.Text;
conn.Open();
SqlDataReader r = cmd.ExecuteReader();
#endregion
#region _assigning the values to tempHotelWithOneRoom
while (r.Read()) {
tempHotelWithOneRoom.Add(new HotelWithOneRoom {
HotelID = int.Parse(r["HotelID"].ToString()),
HotelName = r["HotelName"].ToString(),
Room = new Room {
RoomID = int.Parse(r["RoomID"].ToString()),
RoomCode = r["RoomCode"].ToString(),
RoomName = r["RoomName"].ToString()
}
});
}
#endregion
foreach (var item in tempHotelWithOneRoom) {
if (tempDistinctHotels.Where(x => x.HotelID == item.HotelID).Count() < 1) {
tempDistinctHotels.Add(new Hotel {
HotelID = item.HotelID,
HotelName = item.HotelName
});
var _tempHotel = tempDistinctHotels.Single(x => x.HotelID == item.HotelID);
var _tempRoomList = new List<Room>();
if (_tempHotel.Rooms != null) {
foreach (var _item in _tempHotel.Rooms) {
_tempRoomList.Add(_item);
}
}
_tempRoomList.Add( new Room {
RoomCode = item.Room.RoomCode,
RoomID = item.Room.RoomID,
RoomName = item.Room.RoomName
});
_tempHotel.Rooms = _tempRoomList.AsQueryable();
} else {
var _tempHotel = tempDistinctHotels.Single(x => x.HotelID == item.HotelID);
var _tempRoomList = new List<Room>();
if (_tempHotel.Rooms != null) {
foreach (var _item in _tempHotel.Rooms) {
_tempRoomList.Add(_item);
}
}
_tempRoomList.Add( new Room {
RoomCode = item.Room.RoomCode,
RoomID = item.Room.RoomID,
RoomName = item.Room.RoomName
});
_tempHotel.Rooms = _tempRoomList.AsQueryable();
}
}
#region _output the result
foreach (var item in tempDistinctHotels) {
Console.WriteLine(
"Hotel Name : " + item.HotelName + ", " + "Room Count : " + item.Rooms.Count()
);
foreach (var item2 in item.Rooms) {
Console.WriteLine("--" + item2.RoomCode + ", " + item2.RoomName);
}
}
#endregion
r.Close();
Console.Read();
}
}
}
}
IMO, if there was a competition on the worst c# code, I would be winning that competition with this code. (Would I?)
So, what is the most optimized way of doing what I do?

C# is not my language of choice but here you go:
Dictionary<int, Hotel> Hotels = new Dictionary<int, Hotel> ();
while (r.Read()) {
if (!Hotels.ContainsKey(r["HotelID"])) {
NewHotel Hotel= new Hotel();
NewHotel.HotelID = r["HotelID"];
Newhotel.HotelName = r["HotelName"];
NewHotel.Rooms = new Dictionary<int, Room> ();
Hotels.Add(NewHotel);
}
Room NewRoom = new Room();
NewRoom.RoomID = r["RoomName"];
NewRoom.RoomCode = r["RoomCode"];
NewRoom.RoomName = r["RoomName"];
Hotels.Items("HotelID").Rooms.Add(NewRoom);
}
Like jpmcclung pointed out, you'll need some Software engineering Skills to create successful Applications. The bigger your Project, the more design and planning is called for.

The best way to get around writing code like this is to study up on the practice of test driven design. This code is screaming for it. To see it in action I would check out Brad Wilson's new TDD Full Throttle video at TekPub (http://shop.tekpub.com/products/ft_tdd_wilson) it is 12 bucks but it will be worth it. Otherwise there are numerous resourses on the subject.
Specifically, why do you need a HotelWithOneRoom? Just add one room to the Rooms list in a regular hotel. Why don't you override .ToString() on the Hotel and use the StringBuilder to create the output line for a hotel? Those are just a few things off the top of my head but if you use TDD it will help organize your design practice and get some of this code out of your way.

Since you include IQueryable in your example, can we assume that LINQ to SQL or EF is an option for your solution? If so, realize that they support projecting into object heirarchies directly.
Asssuming you have associations set between your tables, it could be as simple as:
var query = from hotel in context.hotels
select new Hotel { HotelID = hotel.HotelID,
HotelName = hotel.HotelName,
Rooms = (from room in hotel.Rooms
select new Room {
RoomID = room.RoomID,
RoomCode = room.RoomCode,
RoomName = room.RoomName })
.Distinct()
};

I think you could start from the beginning here and avoid some confusion by renaming your Tables. I think your table names should be Hotel, Room and RoomType (I'm not a fan of pluralized table names, but that's beside the point).
To think in 'Domain' terms, you have a Hotel. A hotel has Rooms. Each room is defined as a type of room, Double, Single, etc...
Anyway, I threw some code together that's doing the same thing yours is doing. It's a little clearer I think.
For database access, I used Massive https://github.com/robconery/massive because it's quick and fun.
Anyway, here is the code I came up with.
class Program {
static void Main(string[] args) {
const string sqlStmnt = #"SELECT h.HotelID, h.HotelName, r.HotelRoomID, rt.RoomTypeCode, rt.RoomTypeName FROM Hotel h INNER JOIN HotelRoom r ON r.HotelID = h.HotelID INNER JOIN RoomType rt ON r.RoomTypeID = rt.RoomTypeID order by h.HotelName, rt.RoomTypeCode";
var context = new HotelContext();
var hotelData = context.Query(sqlStmnt);
var hotelList = new List<Hotel>();
//Load our objects
foreach (dynamic data in hotelData) {
int hotelID = data.HotelID;
var hotel = hotelList.Where(h => h.HotelID == hotelID).FirstOrDefault()
?? new Hotel() {HotelName = data.HotelName};
hotel.AddRoom(new HotelRoom { HotelRoomID = data.HotelRoomID, RoomType = new RoomType{ TypeCode = data.RoomTypeCode, TypeDescription = data.RoomTypeName}});
if (hotel.HotelID != 0) {continue;}
hotel.HotelID = hotelID;
hotelList.Add(hotel);
}
//Display our output
foreach (var hotel in hotelList) {
Console.WriteLine("Hotel Name : " + hotel.HotelName + ", Room Count : " + hotel.HotelRooms.Count());
foreach (var room in hotel.HotelRooms) {
Console.WriteLine("--" + room.RoomType.TypeCode + ", " + room.RoomType.TypeDescription);
}
}
Console.ReadLine();
}
}
Here is my Database stuff.
public class HotelContext : DynamicModel {
public HotelContext():base("test") {
PrimaryKeyField = "HotelID";
TableName = "Hotel";
}
}
Here are the classes I used. Couldn't ever figure out what your HotelWithOneRoom was meant for.
public class Hotel{
private readonly List<HotelRoom> _rooms = new List<HotelRoom>();
public int HotelID { get; set; }
public string HotelName { get; set; }
public void AddRoom(HotelRoom room) {_rooms.Add(room);}
public IQueryable<HotelRoom> HotelRooms {get {return _rooms.AsQueryable();}}
}
public class HotelRoom {
public int HotelRoomID { get; set; }
public RoomType RoomType { get; set; }
}
public class RoomType {
public string TypeCode { get; set; }
public string TypeDescription { get; set; }
}

Related

How can i create a class with a property for each country and it's items?

In the top of the class
public class Country
{
public string country { get; set; }
}
And how i build the links
public void ImagesLinks()
{
try
{
int counter = 0;
int cnt = 0;
foreach (string countryCode in countriescodes)
{
imagesUrls.Add(countriesnames[counter]);
counter++;
cnt++;
for (; cnt < DatesAndTimes.Count(); cnt++)
{
string imageUrlIrTrue = firstUrlPart + countryCode + secondUrlPart + DatesAndTimes[cnt] + thirdUrlPart + "true";
string imageUrlIrFalse = firstUrlPart + countryCode + secondUrlPart + DatesAndTimes[cnt] + thirdUrlPart + "false";
imagesUrls.Add(imageUrlIrTrue);
imagesUrls.Add(imageUrlIrFalse);
if (cnt % 10 == 0)
break;
}
}
}
catch(Exception err)
{
string myerr = err.ToString();
}
}
What i have in the end is a List with names and the links of each name.
For example in the index 0 i have the name: Europe
Then then ext 18 indexs are links of Europe
Then the next name is in index 21: Alps
And then the next 18 indxs of Alps
What i want to do is using the class Country is when i will type for example:
Country. ( After the point i will have properties of all the names Europe ,Alps and so on so i can select one of the names ) Same like if i will type for example File. so after the point i will have properties like Create Copy and so on so when i will type Country i will have all the countries names Europe, Alps....
And then if i will make a loop over one of the names it will loop over it's 18 items. For example:
For (int i = 0; i < Country.Europe; i++)
{
// something to do with Country.Europe[i]
}
Or
For (int i = 0; i < Country.Alps; i++)
{
// something to do with Country.Alps[i]
}
So maybe each name/country should be a List of it self ?
For (int i = 0; i < Country.Europe.Count(); i++)
{
// something to do with Country.Europe[i]
}
But the idea is that i will be able easy to select a name from a properties list and when loop over the name it will loop over it's 18 items.
I threw this together real fast - it is how I would probably handle it. I added a little more, I think you just need a class to handle countries. In any case, you would need to adjust your loop to create this structure, so this isn't a perfect solution - but it's how I would do it. You could also use linq instead of loops, I did this more as a class-based answer than a "pretty" answer.
namespace classTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
World newWorld = new World();
Continent Europe = new Continent();
Europe.name = "Europe";
Country England = new Country();
England.name = "England";
List<string> imageUrl = new List<string>();
imageUrl.Add("url1-England");
imageUrl.Add("url2-England");
imageUrl.Add("url3-England");
England.imageUrls = imageUrl;
Europe.countries.Add(England);
newWorld.continents.Add(Europe);
Country France = new Country();
France.name = "France";
imageUrl = new List<string>();
imageUrl.Add("url1-France");
imageUrl.Add("url2-France");
imageUrl.Add("url3-France");
France.imageUrls = imageUrl;
Europe.countries.Add(France);
foreach (Continent continent in newWorld.continents)
{
Console.WriteLine(continent.name);
foreach (Country country in continent.countries)
{
Console.WriteLine(country.name);
foreach(string imageUri in country.imageUrls)
{
Console.WriteLine(imageUri);
}
}
}
}
}
public class World
{
public List<Continent> continents;
public World()
{
continents = new List<Continent>();
}
}
public class Continent
{
public string name;
public List<Country> countries { get; set; }
public Continent()
{
name = string.Empty;
countries = new List<Country>();
}
}
public class Country
{
public string name { get; set; }
public List<string> imageUrls { get; set; }
public Country()
{
name = string.Empty;
imageUrls = new List<string>();
}
}
}
In the following solution, I use an outer wrapper Country that provides static references to instances for the continents (e.g. Europe). The continents implement IEnumerable, so you can iterate over all countries of this continent or use LINQ to filter them.
public class CountryData : IEquatable<CountryData>{
public string Link { get; set; }
public bool Equals(CountryData other) {
if (other == null) {
return false;
}
return StringComparer.Ordinal.Equals(Link, other.Link);
}
public override int GetHashCode() {
return Link.GetHashCode();
}
}
public static class Country {
public static readonly Europe Europe = new Europe();
}
public class Europe : IEnumerable<CountryData> {
private List<CountryData> All => new List<CountryData> {
Austria,
Belgium
};
public CountryData Austria = new CountryData { Link = #"\Country\Austria" };
public CountryData Belgium = new CountryData { Link = #"\Country\Belgium" };
IEnumerator<CountryData> IEnumerable<CountryData>.GetEnumerator() {
return All.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return All.GetEnumerator();
}
}
Usage examples:
var austria = Country.Europe.Austria;
var belgium = Country.Europe.Single(c => c.Link.Contains("Belgium"));
foreach (var european in Country.Europe) {
Console.WriteLine(european.Link);
}
Edit
If you want to compare countries, CountryData must implement IEquatable<CountryData>
Usage example:
var isSame = Country.Europe.Austria == Country.Europe.Belgium;
// isSame is false

Populate Model class from Data in Backend

I have a database that has two tables as follows, Please ignore the data but the format looks as follows
Now I have a Model class that is constructed as follows
public class FamilyModel
{
public string Name { get; set; }
public List<FamilyModel> FamilyList { get; set; }
public FamilyModel()
{
FamilyList = new List<FamilyModel>();
}
}
Now all I want is to get data from the two tables and populate the list.
So I have a stored procedure that returns data as follows
So I have written some code to populate the above class. But it dosent work. I get a count of 5 when I debug. I want the count to be 2 and when expanded I want something like FamilyA ->{Nick, Tom, Pam}.. FamilyB->{Harry} and so on. Please help fixing this code.
public static FamilyModel familyData()
{
//FamilyModel fml = new FamilyModel();
//fml.FamilyList = new List<FamilyModel>();
using (SqlConnection con = new SqlConnection(#"Data Source=(LocalDB)\v11.0; AttachDbFilename=|DataDirectory|\Families.mdf; Integrated Security=True; Connect Timeout=30;"))
{
con.Open();
SqlCommand cmd = new SqlCommand("sp_GetFamilies", con);
cmd.CommandType = CommandType.StoredProcedure;
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read()) {
FamilyModel fm = new FamilyModel();
fm.Name = dr["FamilyName"].ToString();
foreach (var item in dr["ChildName"].ToString())
{
if (Convert.ToInt32(dr["id"]) == Convert.ToInt32(dr["FID"]))
{
fm.FamilyList.Add(new FamilyModel() { Name = dr["ChildName"].ToString() });
}
}
}
return fm;
}
}
Here is some source code that should get the right idea across. Below it, I've included some explanation for what's going on.
using Dapper;
public class FamilyModel
{
public int Id { get; set;}
public string FamilyName { get; set; }
public List<Person> Members { get; set; } = new List<Person>();//Initializer for Auto-Property, C#6<= only
}
public class Person
{
public int Id { get; set;}
public string Name { get; set; }
}
public class DatabasePOCO
{
public string FamilyName { get; set; }
public string ChildName { get; set; }
public int Fid { get; set; }
public int Id { get; set;}
}
void Main()
{
using (IDbConnection conn = new SqlConnection("..."))
{
conn.Open();
var raw = conn.Query<DatabasePOCO>("sp_GetFamilies",
commandType: CommandType.StoredProcedure);//Could be dynamic, not typed
var familyList = raw
.GroupBy(x => x.Fid)
.Select(x =>
{
var rawMembers = x.ToList();
var fId = x.First().Fid;
var fName = x.First().FamilyName;
var members = rawMembers.Select(y => new Person
{
Id = y.Id,
Name = y.ChildName
});
return new FamilyModel
{
Id = fId,
FamilyName = fName,
Members = members.ToList()
};
});
//Whatever else you want to do here
}
}
Consider using Dappper. It is a great ORM that makes accessing data from database really easy. It's designed to work with SQL Server, but I've had success using Oracle too, and most other RMDBS systems will probably work.
Consider using Slapper. If you have control over your stored procedure, this can reduce a lot of the boilerplate code below.
If you use Dapper (I hope you do), you can play around with C# dynamic objects, or you can create a POCO to help get some type enforcement on your code.
Understand if you care about reference equality. The code I provided below does not enforce reference equality of objects. Reference equality, in my experience, doesn't buy you much and is a pain to enforce.
You need to distinguish between a new row in the data set and a new FamilyModel. One way to do this is to declare a list of models, then look up the "right" one before you add the current child row:
var rootModel = new FamilyModel();
rootModel.Name = "root";
// ... Set up data reader ...
while (dr.Read())
{
//This requires support for the Id in your FamilyModel:
var id = (int)dr["Id"];
//You could also use ".Single(...)" here
var fm = rootModel.FamilyList.Where(x => x.Id == id).First();
if (fm == null)
{
fm = new FamilyModel();
fm.Name = dr["FamilyName"].ToString();
rootModel.FamilyList.Add(fm);
}
fm.FamilyList.Add(new FamilyModel() { Name = dr["ChildName"].ToString() });
}
For each row in your database query, you'll:
Try to look up that family in your list
If you don't find one, create a new one. Add it to your top-level list.
Add the child name as a sub-element of the "current" family.

Conditional Joins With Linq

Is there a way to progressively / conditionally add joins to a query? I am creating a custom reporting tool for a client, and the client is given a list of objects he/she can select to query on. There will always be a base object used in the query ("FWOBid").
So, for example, if the customer selects objects "FWOBid", "FWOItem", and "FWOSellingOption", I'd want to do this:
var query = from fb in fwoBids
// if "FWOSellingOption", add this join
join so in sellingOptions on fb.Id equals so.BidId
// if "FWOItem", add this join
join i in fwoItems on fb.Id equals i.FWOBidSection.BidId
// select "FWOBid", "FWOItem", and "FWOSellingOption" (everything user has selected)
select new { FWOBid = fb, FWOSellingOption = so, FWOItem = i };
The trick is the customer can select about 6 objects that are all related to each other, resulting in many different combinations of joins. I'd like to avoid hard coding those if possible.
One option is to do some custom join combined with left joins.
A decent TSQL backend should not get any drawbacks in terms of performance for always using all the joins, since the optimers would just remove the join if the condition is always false. But this should be checked out.
bool joinA = true;
bool joinB = false;
bool joinC = true;
var query = from fb in fwoBids
join so in sellingOptions on new { fb.Id, Select = true } equals new { Id = so.BidId, Select = joinA } into js
from so in js.DefaultIfEmpty()
join i in fwoItems on new { fb.Id, Select = true } equals new { Id = i.FWOBidSection.BidId, Select = joinB } into ji
from i in ji.DefaultIfEmpty()
join c in itemsC on new { fb.Id, Select = true } equals new { Id = c.BidId, Select = joinC }
select new
{
FWOBid = fb,
FWOSellingOption = so,
FWOItem = i,
ItemC = c
};
In the Linq query syntax this is not possible, or looking at the other answers hardly readable. Not much more readable but another possibility would be to use the extension methods (sort of pseudo code):
bool condition1;
bool condition2;
List<Bid> bids = new List<Bid>();
List<SellingOption> sellingOptions = new List<SellingOption>();
List<Item> items = new List<Item>();
var result = bids.Select(x => new {bid = x, sellingOption = (SellingOption)null, item = (Item)null});
if (condition1)
result = result.Join(
sellingOptions,
x => x.bid.Id,
x => x.BidId,
(x, sellingOption) => new { x.bid, sellingOption, item = (Item)null });
if (condition2)
result = result.Join(
items,
x => x.bid.Id,
x => x.BidId,
(x, item) => new { x.bid, x.sellingOption, item });
Just see this as a sort of a concept. It is essentially the same that Peter Duniho did.
The thing is, if you don't want to immediately join on all options if not necessary, then it won't look that nice. Perhaps you should try to join all now and don't worry about performance. Have you ever measured how slow or fast it might be? Think of it as "I don't need it now!". If performance is indeed a problem, then you can act on it. But if it is not, and you won't know if you never tried, then leave it as the six joins you mentioned.
It's hard to provide a really good example solution without a really good example problem. However, what I mean by "chain the queries" is something like this:
var query = from x in dba select new { A = x, B = (B)null, C = (C)null };
if ((joinType & JoinType.B) != 0)
{
query = from x in query
join y in dbb on x.A.Id equals y.Id
select new { A = x.A, B = y, C = x.C };
}
if ((joinType & JoinType.C) != 0)
{
query = from x in query
join y in dbc on x.A.Id equals y.Id
select new { A = x.A, B = x.B, C = y };
}
That is, based on the appropriate condition, query the previous result with another join. Note that to do this successfully, each query must produce the same type. Otherwise, it's not possible to assign a new query to the previous query result variable.
Note that while in the above, I simply have a separate property for each possible input type, I could have instead had the type simply have properties for the input columns, Id, Name, and then the Text properties from the B and C types (which would have to be named differently in the query result type, e.g. TextB and TextC). That would look like this:
var query = from x in dba select new { Id = x.Id, Name = x.Name,
TextB = (string)null, TextC = (string)null };
if ((joinType & JoinType.B) != 0)
{
query = from x in query
join y in dbb on x.Id equals y.Id
select new { Id = x.Id, Name = x.Name, TextB = y.Text, TextC = x.TextC };
}
if ((joinType & JoinType.C) != 0)
{
query = from x in query
join y in dbc on x.Id equals y.Id
select new { Id = x.Id, Name = x.Name, TextB = x.TextB, TextC = y.Text };
}
Here is a complete code example that includes the above logic in a runnable program:
class A
{
public string Name { get; private set; }
public int Id { get; private set; }
public A(string name, int id)
{
Name = name;
Id = id;
}
public override string ToString()
{
return "{" + Name + ", " + Id + "}";
}
}
class B
{
public int Id { get; private set; }
public string Text { get; private set; }
public B(int id, string text)
{
Id = id;
Text = text;
}
public override string ToString()
{
return "{" + Id + ", " + Text + "}";
}
}
class C
{
public int Id { get; private set; }
public string Text { get; private set; }
public C(int id, string text)
{
Id = id;
Text = text;
}
public override string ToString()
{
return "{" + Id + ", " + Text + "}";
}
}
[Flags]
enum JoinType
{
None = 0,
B = 1,
C = 2,
BC = 3
}
class Program
{
static void Main(string[] args)
{
A[] dba =
{
new A("A1", 1),
new A("A2", 2),
new A("A3", 3)
};
B[] dbb =
{
new B(1, "B1"),
new B(2, "B2"),
new B(3, "B3")
};
C[] dbc =
{
new C(1, "C1"),
new C(2, "C2"),
new C(3, "C3")
};
JoinType joinType;
while ((joinType = _PromptJoinType()) != JoinType.None)
{
var query = from x in dba select new { A = x, B = (B)null, C = (C)null };
if ((joinType & JoinType.B) != 0)
{
query = from x in query
join y in dbb on x.A.Id equals y.Id
select new { A = x.A, B = y, C = x.C };
}
if ((joinType & JoinType.C) != 0)
{
query = from x in query
join y in dbc on x.A.Id equals y.Id
select new { A = x.A, B = x.B, C = y };
}
foreach (var item in query)
{
Console.WriteLine(item);
}
Console.WriteLine();
}
}
private static JoinType _PromptJoinType()
{
JoinType? joinType = null;
do
{
Console.Write("Join type ['A' for all, 'B', 'C', or 'N' for none]");
ConsoleKeyInfo key = Console.ReadKey();
Console.WriteLine();
switch (key.Key)
{
case ConsoleKey.A:
joinType = JoinType.BC;
break;
case ConsoleKey.B:
joinType = JoinType.B;
break;
case ConsoleKey.C:
joinType = JoinType.C;
break;
case ConsoleKey.N:
joinType = JoinType.None;
break;
default:
break;
}
} while (joinType == null);
return joinType.Value;
}
}
I hope this is an improvement over previous answers.
public class Bids
{
public int Id { get; set; }
public double Price { get; set; }
}
public class BidSection
{
public int BidId { get; set; }
}
public class SellingOptions
{
public int BidId { get; set; }
public int Quantity { get; set; }
}
public class Item
{
public int ItemId { get; set; }
public BidSection FWOBidSection { get; set; }
}
public class ConditionalJoin
{
public bool jOpt1 { get; set; }
public bool jOpt2 { get; set; }
public ConditionalJoin(bool _joinOption1, bool _joinOption2)
{
jOpt1 = _joinOption1;
jOpt2 = _joinOption2;
}
public class FBandSo
{
public Bids FWOBids { get; set; }
public SellingOptions FWOSellingOptions { get; set; }
}
public class FBandI
{
public Bids FWOBids { get; set; }
public Item FWOItem { get; set; }
}
public void Run()
{
var fwoBids = new List<Bids>();
var sellingOptions = new List<SellingOptions>();
var fwoItems = new List<Item>();
fwoBids.Add(new Bids() { Id = 1, Price = 1.5 });
sellingOptions.Add(new SellingOptions() { BidId = 1, Quantity = 2 });
fwoItems.Add(new Item() { ItemId = 10, FWOBidSection = new BidSection() { BidId = 1 } });
IQueryable<Bids> fb = fwoBids.AsQueryable();
IQueryable<SellingOptions> so = sellingOptions.AsQueryable();
IQueryable<Item> i = fwoItems.AsQueryable();
IQueryable<FBandSo> FBandSo = null;
IQueryable<FBandI> FBandI = null;
if (jOpt1)
{
FBandSo = from f in fb
join s in so on f.Id equals s.BidId
select new FBandSo()
{
FWOBids = f,
FWOSellingOptions = s
};
}
if (jOpt2)
{
FBandI = from f in fb
join y in i on f.Id equals y.FWOBidSection.BidId
select new FBandI()
{
FWOBids = f,
FWOItem = y
};
}
if (jOpt1 && jOpt2)
{
var query = from j1 in FBandSo
join j2 in FBandI
on j1.FWOBids.Id equals j2.FWOItem.FWOBidSection.BidId
select new
{
FWOBids = j1.FWOBids,
FWOSellingOptions = j1.FWOSellingOptions,
FWOItems = j2.FWOItem
};
}
}
}

The specified table does not exist[entity]

I have spent hours trying to figure out why my database cannot find the table I have found numerous examples and none have seemed to help. I have created a separate class to handle the database operations so I can use it on multiple pages.
Here is the code
[Table]
public class MatchItem
{
[Column(IsPrimaryKey = true, CanBeNull=false,IsDbGenerated=true)]
public int MatchID { get; set; }
[Column(CanBeNull = false)]
public string MatchNumber { get; set; }
[Column(CanBeNull = false)]
public string EventName { get; set; }
[Column(CanBeNull = false)]
public DateTime Time { get; set; }
[Column(CanBeNull = false)]
public string[] RedTeams { get; set; }
[Column(CanBeNull = false)]
public string[] BlueTeams { get; set; }
[Column(CanBeNull = false)]
public int RedFinal { get; set; }
[Column(CanBeNull = false)]
public int BlueFinal{ get; set; }
}
Here is the Data context
public class MatchDataContext:DataContext
{
public MatchDataContext(string connectionString) :
base(connectionString)
{
}
public Table<MatchItem> Matches
{
get
{
return this.GetTable<MatchItem>();
}
}
}
I made a class so I could use it on multiple pages
public class MatchDBManager
{
private static string connectionString = #"Data Source=isostore:/DB.sdf";
public MatchDBManager()
{
initialize();
}
public void initialize()
{
using (MatchDataContext Mchdb = new MatchDataContext(connectionString))
{
if (Mchdb.DatabaseExists())
{
Console.WriteLine("DB already exists");
}
else
{
Mchdb.CreateDatabase();
Console.WriteLine("DB created");
}
}
}
public void addMatchData(IList<MatchItem> data)
{
//this.clearData();
//initialize();
using (MatchDataContext Mchdb = new MatchDataContext(connectionString))
{
Mchdb.Matches.InsertAllOnSubmit(data);
Mchdb.SubmitChanges();
}
}
public IList<MatchItem> getTeamData(string teamNum)
{
IList<MatchItem> MatchList = null;
using (MatchDataContext Mchdb = new MatchDataContext(connectionString))
{
IQueryable<MatchItem> mchQuery = from mch in Mchdb.Matches where (mch.RedTeams[0] == teamNum || mch.RedTeams[1] == teamNum || mch.RedTeams[2] == teamNum || mch.BlueTeams[0] == teamNum || mch.BlueTeams[1] == teamNum || mch.BlueTeams[2] == teamNum) select mch;
MatchList = mchQuery.ToList();
}
return MatchList;
}
public IList<MatchItem> getEventData(string eventID)
{
IList<MatchItem> MatchList = null;
using (MatchDataContext Mchdb = new MatchDataContext(connectionString))
{
IQueryable<MatchItem> mchQuery = from mch in Mchdb.Matches where mch.Event == eventID select mch;
MatchList = mchQuery.ToList();
}
return MatchList;
}
private void clearData()
{
using (MatchDataContext Mchdb = new MatchDataContext(connectionString))
{
if (Mchdb.DatabaseExists())
{
Mchdb.DeleteDatabase();
}
}
}
}
I have the error The specified table does not exist[Match].
Added here is where I download
public IList<MatchItem> ParseXML(XmlReader reader)
{
//List<string> save = new List<string>();
List<MatchItem> MatchList= new List<MatchItem>();
XElement matchData;
matchData = XElement.Load(reader);
StringBuilder output = new StringBuilder();
int count = 0;
var matches = from item
in matchData.Elements("match")
select item;
foreach (XElement eachmatch in matches)
{
MatchItem mch = new MatchItem();
string Time = ((eachmatch.Element("pubdate").Value).ToString());
mch.EventName = ((eachmatch.Element("event").Value).ToString());
mch.MatchNumber = ((eachmatch.Element("mch").Value).ToString() + (eachmatch.Element("typ").Value).ToString());
string[] RT = { eachmatch.Element("red1").Value.ToString(), eachmatch.Element("red2").Value.ToString(), eachmatch.Element("red3").Value.ToString() };
string[] BT = { eachmatch.Element("blue1").Value.ToString(), eachmatch.Element("blue2").Value.ToString(), eachmatch.Element("blue3").Value.ToString() };
string RF = ((eachmatch.Element("rfin").Value).ToString());
string BF = ((eachmatch.Element("bfin").Value).ToString());
// Time = Time.Substring(0, (Time.IndexOf("+") - 1));
mch.Time = DateTime.Parse(Time);
mch.RedTeams = RT;
mch.BlueTeams = BT;
mch.RedFinal = int.Parse(RF);
mch.BlueFinal= int.Parse(BF);
mch.MatchID = count;
count += 1;
MatchList.Add(mch);
}
return MatchList;
}
This is where I call this method
void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
initializeDB();
if (e.Error == null)
{
XmlReader reader = XmlReader.Create(new StringReader(e.Result));
DownloadInfo di = new DownloadInfo();
IList <MatchItem>data= di.ParseXML(reader);
outputer(data);
addData(data.ToList<MatchItem>());
}
else
{
IList<MatchItem> data = getTeamData(strMyTeam);
outputer(data);
}
}
I ended up removing the DatabaseManager class and putting the functions in the main code
Then I output them to the screen here
public void outputer(IList<MatchItem> mch)
{
for (int i = 0; i < mch.Count; i++)
{
Score sc = new Score();
sc.Width = lsbData.Width;
sc.Height = sc.Height;
sc.Time = mch[i].Time.ToString();
sc.Event = mch[i].EventName;
sc.RT = mch[i].RedTeams[0] + " " + mch[i].RedTeams[1] + " " + mch[i].RedTeams[2];
sc.BT = mch[i].BlueTeams[0] + " " + mch[i].BlueTeams[1] + " " + mch[i].BlueTeams[2];
sc.RF = mch[i].RedFinal.ToString();
sc.BF = mch[i].BlueFinal.ToString();
lsbData.Items.Add(sc);
}
}
*note:score is a custom control that works(and worked) before the database code *
I don't see where you actually create a Match Object.
if you have you need to include that code in the question as well. and if you haven't, that would explain why it doesn't exist.
Addition
in order to add Match Objects to a list you will have to create the objects first then add them to the list, I don't think you can create the whole list of objects before creating each individual object.
more Additional Information
the object still needs to be created before you can add items to it. that is what the error is telling you. you don't have the object to insert data into.
Match Table1 = new Match();
this creates a new Match object which allows you to access the pieces of the object and insert data into the object like this
Table1.MatchNumber = 42
you can't add to something to a memory location until you set aside that memory location for that specific person and give it a name.
when you create that class you can add functions and all sorts of fun stuff to it, but you can't use any of it until you have created a Match Object.
you can't add something to a list that doesn't exist, you have to create the Match Object first, then add it to the list

Result Set Stored on Models - C# .NET 2.0

I have a function that gets the data in the database. Below are the code.
public DataTable getAllTransaction(OleDbConnection conn)
{
OleDbDataAdapter oleAdapter = new OleDbDataAdapter();
string query = "";
DataTable tblResult = new DataTable();
query = #"SELECT t.id AS `Transaction ID`,
c.id AS `Client ID`,
c.clientname AS `Client Name`,
t.cashvalue AS `Cash Value`,
t.amount AS `Amount`,
t.transdate AS `Transaction Date`,
t.remarks AS `Remarks`
FROM client AS c
INNER JOIN `transaction` AS t
ON c.id=t.clientid";
oleAdapter.SelectCommand = new OleDbCommand(query, conn);
oleAdapter.Fill(tblResult);
return tblResult;
}
My problem is, how could I store the result set into model (e.g. I don't want to return DataTable). Below is my Model Class.
Class TransactionModel
{
public int transID { get; set; }
public int clientID { get; set; }
public string clientName { get; set; }
public double cashValue { get; set; }
public double amout { get; set; }
public DateTime transDate { get; set; }
public string remarks { get; set; }
}
You could use LINQ and do:
var tranModel = from r in tblResult.Tables[0]
select new TransactionModel
{
transId = r.Field<int>("transID"),
clientId = r.Field<int>("clientId"),
clientName = r.Field<string>("ClientName")
}
Note since you are using .NET 2.0. LINQ is not directly available. You will have to use
Something like LINQBridge: http://www.albahari.com/nutshell/linqbridge.aspx
Another alternative is to loop through all of the rows in tblResult and have a generic list of TransactionModel. For instance:
List<TransactionModel> tModels = new List<TransactionModel>();
foreach (var row in tblResult.Tables[0].Rows)
{
tModels.Add(new TransactionModel
{
transId = row["TransId"],
clientId = row["ClientId"],
clientName = row["clientName"]
});
}
Because LINQ isn't available in .NET 2, you'd have to loop through the items yourself and transform them into your type. Something like this:
DataTable transactions = getAllTransactions();
List<TransactionModel> model = new List<TransactionModel>();
foreach (DataRow transaction in transactions.Rows)
{
TransactionModel tran = new TransactionModel
{
transId = transaction.Field<int>("transID"),
clientId = transaction.Field<int>("clientId"),
clientName = transaction.Field<string>("ClientName")
//etc...
};
model.Add(tran);
}
Do something like:
List<TransactionModel> TransactionItems = tblResult.AsEnumerable().Select(r =>
new TransactionModel
{
transID = r.Field<int>("TransactionID"),
clientID = r.Field<int>("clientID"),
and so on.....
}).ToList();
return items;

Categories

Resources