I'm fairly new to c# and having difficulty with lists.
I'm creating an application that takes in a user's name, age, and address, then stores it in a list when the user clicks the 'add' button.
I'm using a GUI with text boxes for user input.
I have made a Customer class and unsure what to do next. I've followed tutorials and other questions but can't seem to find an answer.
public class Customer
{
private string name;
private Int32 age;
private string address1;
private string address2;
private string address3;
public string Name
{
get
{
return name;
}
// if name is blank throw argument asking user for input
set
{
if (name == "")
{
throw new ArgumentException("Please enter your name");
}
else
{
name = value;
}
}
}
public Int32 Age
{
get
{
return age;
}
set
{
age = value;
}
}
// get/set address
public string Address1
{
get
{
return address1;
}
set
{
if (address1 == "")
{
throw new ArgumentException("Please enter your address");
}
else
{
address1 = value;
}
}
}
public string Address2
{
get
{
return address2;
}
set
{
if (address2 == "")
{
throw new ArgumentException("Please enter your adress");
}
else
{
address2 = value;
}
}
}
public string Address3
{
get
{
return address3;
}
set
{
if (address3 == "")
{
throw new ArgumentException("Please enter your adress");
}
else
{
address3 = value;
}
}
}
This is an example of simple Windows Forms form that will give you an idea. Basically you would like to store the list of customers in private generic list variable. More about how to use generic and non-generic lists in C# here.
public partial class Form1 : Form
{
// Initialize private generic list where all customers will be stored at runtime
private List<Customer> _customers = new List<Customer>();
private void buttonAddCustomer_Click(object sender, EventArgs e)
{
// It might be a good idea to add some validation logic before assigning the input values
var newCustomer = new Customer();
newCustomer.Name = this.textBoxName.Text;
newCustomer.Age = Convert.ToInt32(this.textBoxAge.Text);
newCustomer.Address1 = this.textBoxAddress1.Text;
newCustomer.Address2 = this.textBoxAddress2.Text;
newCustomer.Address3 = this.textBoxAddress3.Text;
_customers.Add(newCustomer);
}
}
I think what you are looking for is in the MakeItHappen() method
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace _41150122
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btn_Go_Click(object sender, EventArgs e)
{
MakeItHappen();
}
private void MakeItHappen()
{
List<Customer> customerList = new List<Customer>();//initialize your List<Customer>
customerList.Add(new Customer { Name = txtbx_Name.Text, Address1 = txtbx_Address1.Text, Age = int.Parse(txtbx_Age.Text) });//add a record to it
}
}
public class Customer
{
private string name;
private Int32 age;
private string address1;
private string address2;
private string address3;
public string Name
{
get
{
return name;
}
// if name is blank throw argument asking user for input
set
{
if (name == "")
{
throw new ArgumentException("Please enter your name");
}
else
{
name = value;
}
}
}
public Int32 Age
{
get
{
return age;
}
set
{
age = value;
}
}
// get/set address
public string Address1
{
get
{
return address1;
}
set
{
if (address1 == "")
{
throw new ArgumentException("Please enter your address");
}
else
{
address1 = value;
}
}
}
public string Address2
{
get
{
return address2;
}
set
{
if (address2 == "")
{
throw new ArgumentException("Please enter your adress");
}
else
{
address2 = value;
}
}
}
public string Address3
{
get
{
return address3;
}
set
{
if (address3 == "")
{
throw new ArgumentException("Please enter your adress");
}
else
{
address3 = value;
}
}
}
}
}
Related
The button function, should take whatever text is in the combo box and place it within sleeper.traintype
private void Btn_Apply_Click(object sender, RoutedEventArgs e)
{
try
{
sleeper.trainType = CmbBox_TrainType.Text;
if (CmbBox_TrainType.Text == "Sleeper")
{
// instantiate the sleeper train
sleeper.trainType = CmbBox_TrainType.Text;
}
}
My sleeper train class (inheriting from overall train class)
public class Sleeper : Train
{
private string _intermediate, _intermediate1, _intermediate2, _intermediate3;
private bool _cabin;
public string intermediate
{
get
{
return _intermediate;
}
set
{
_intermediate = value;
}
}
public string intermediate1
{
get
{
return _intermediate1;
}
set
{
_intermediate1 = value;
}
}
public string intermediate2
{
get
{
return _intermediate2;
}
set
{
_intermediate2 = value;
}
}
public string intermediate3
{
get
{
return _intermediate3;
}
set
{
_intermediate3 = value;
}
}
The train class:
public class Train
{
private string _trainID, _departureDay, _departureStation, _destinationStation, _departureTime, _trainType;
private bool _firstClass;
public string timePunctuation = ":";
public string dayPunctuation = "/";
public string trainID
{
get
{
return _trainID;
}
set
{
// check if the vlaue has letters & numbers and that the length is correct
if(value.Length == 4 && Regex.IsMatch(value, "[A-Z][0-9]"))
{
_trainID = value;
}
else
{
throw new FormatException("That train ID is not valid! (Example: AA11)");
}
}
}
public string departureDay
{
get
{
return _departureDay;
}
set
{
if(value.Length == 0)
{
throw new FormatException("You need to choose a departure day!");
} else
{
_departureDay = value;
}
}
}
public string departureTime
{
get
{
return _departureTime;
}
set
{
if(value.Length != 5 || value.Contains(timePunctuation) == false)
{
throw new FormatException("The time must be in this format: (11:11 or 03:22)");
} else
{
_departureTime = value;
}
}
}
public string departureStation
{
get
{
return _departureStation;
}
set
{
if(value.Length == 0)
{
throw new FormatException("You must enter a departure station!");
} else
{
_departureStation = value;
}
}
}
public string destinationStation
{
get
{
return _destinationStation;
}
set
{
if(value.Length == 0)
{
throw new FormatException("You must enter a destination!");
} else
{
_departureStation = value;
}
}
}
public string trainType
{
get
{
return _trainType;
}
set
{
value = _trainType;
}
}
}
I'm using a combobox with three options "Sleeper", "Stopping" and "Express". When using breakpoints next to sleeper.trainType = CmbBox_TrainType.Text; it creates my class but states that my sleeper.trainType variable is null. But it says that
CmbBox_TrainType = "Sleeper"
Instantiate sleeper at the start with Sleeper sleeper = new Sleeper();
but have also tried to put it in the if and just before sleeper.trainType = CmbBox_TrainType.Text;
So I'm building an application in WPF using MVVM and I want to save various object model data as XML. Using Serialize an object to XML I can correctly serialize objects to XML, but the issue I'm having is with the MVVM itself.
I can't directly access the Model of the object within the ICommand segments of the ViewModel code (E.G. When I hit save, that goes to an ICommand method inside the ViewModel).
I've made the Model is question serializable, I just have no way to pass it directly to my Serialize method (which is contained in it's own static Helper class) so even if I weren't getting "Unexpected type" spit back at me (since VieWModel is not serializable) I'd end up with a lot of excess garbage, not just the Model class being serialized.
I'm not sure if I'm just designing this incorrectly, or if there's a better way to do it or...?
P.S. All of these fields are just being written into TextBox controls that are bound appropriately. Right now I'm only trying to do the name fields to avoid any kind of issues with other data types not working right.
EDIT: As requested in a comment, the goal right now is just to be able to write some bits of text in a few text boxes (First, middle, last names), then save that to an XML file.
Summarized Model in question:
namespace XMLaw.Model
{
[Serializable]
public class ClientModel
{
private string firstName { get; set; }
private string middleName { get; set; }
private string lastName { get; set; }
private DateTime dateOfBirth { get; set; }
private string ssn { get; set; } //Format: AA ## ## ## A, spaces optional
private string address { get; set; }
private string phone { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#region Name Properties
public string FirstName
{
get { return firstName; }
set
{
if( firstName != value )
{
firstName = value;
OnPropertyChanged("FirstName");
}
}
}
public string MiddleName
{
get { return middleName; }
set
{
if (middleName != value)
{
middleName = value;
OnPropertyChanged("MiddleName");
}
}
}
public string LastName
{
get { return lastName; }
set
{
if (lastName != value)
{
lastName = value;
OnPropertyChanged("LastName");
}
}
}
#endregion
public DateTime DateOfBirth
{
get { return dateOfBirth; }
set
{
if ( dateOfBirth != value )
{
DateTime dt = Convert.ToDateTime(value); //This will probably need to revisited since DateTime objects are fucking stupid
dateOfBirth = dt.Date;
OnPropertyChanged("DateOfBirth");
}
}
}
public string SSN
{
get { return ssn; }
set
{
if( ssn != value)
{
ssn = value;
OnPropertyChanged("SSN");
}
}
}
public string Address
{
get { return address; }
set
{
if( address != value)
{
address = value;
OnPropertyChanged("Address");
}
}
}
public string Phone
{
get { return phone; }
set
{
if( phone != value )
{
phone = value;
OnPropertyChanged("Phone");
}
}
}
}
}
And the ViewModel in question (The Save command that calls the serialization is at the bottom)
namespace XMLaw.ViewModel
{
public class ClientViewModel : INotifyPropertyChanged
{
private ClientModel client;
private string displayMessage;
private ICommand btnSave;
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public ClientViewModel()
{
client = new ClientModel();
}
public ClientModel ClientModel
{
get { return client; }
}
public string DisplayMessage
{
get { return displayMessage; }
set
{
if( displayMessage != value)
{
displayMessage = value;
OnPropertyChanged("DisplayMessage");
}
}
}
public ICommand SaveCommand
{
get
{
if (btnSave == null)
btnSave = new Save();
return btnSave;
}
set { btnSave = value; }
}
protected class Save : ICommand
{
public bool CanExecute(object param) { return true; }
public event EventHandler CanExecuteChanged; //Compiler yells at you if you don't implement this from inhereted ICommand
public void Execute(object param)
{
ClientViewModel viewModel = (ClientViewModel)param;
//TODO: Insert XML serialization and save to a file
var xml = Helper.Serialize(param);
//Placeholder to make sure the button works
viewModel.DisplayMessage = "You clicked the button at " + DateTime.Now;
}
}
}
}
And the Serailization method I shamelessly took from the above link
public static class Helper
{
public static string Serialize<T>(this T value)
{
if (value == null)
{
return string.Empty;
}
try
{
var xmlserializer = new XmlSerializer(typeof(T));
var stringWriter = new StringWriter();
using (var writer = XmlWriter.Create(stringWriter))
{
xmlserializer.Serialize(writer, value);
return stringWriter.ToString();
}
}
catch (Exception ex)
{
throw new Exception("An error occurred", ex);
}
}
}
Change your Client-Model to this:
[Serializable]
public class ClientModel
{
private string firstName;
private string middleName;
private string lastName;
private DateTime dateOfBirth;
private string ssn;
private string address;
private string phone;
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#region Name Properties
public string FirstName {
get { return firstName; }
set {
if (firstName != value)
{
firstName = value;
OnPropertyChanged("FirstName");
}
}
}
public string MiddleName {
get { return middleName; }
set {
if (middleName != value)
{
middleName = value;
OnPropertyChanged("MiddleName");
}
}
}
public string LastName {
get { return lastName; }
set {
if (lastName != value)
{
lastName = value;
OnPropertyChanged("LastName");
}
}
}
#endregion
public DateTime DateOfBirth {
get { return dateOfBirth; }
set {
if (dateOfBirth != value)
{
DateTime dt = Convert.ToDateTime(value); //This will probably need to revisited since DateTime objects are fucking stupid
dateOfBirth = dt.Date;
OnPropertyChanged("DateOfBirth");
}
}
}
public string SSN {
get { return ssn; }
set {
if (ssn != value)
{
ssn = value;
OnPropertyChanged("SSN");
}
}
}
public string Address {
get { return address; }
set {
if (address != value)
{
address = value;
OnPropertyChanged("Address");
}
}
}
public string Phone {
get { return phone; }
set {
if (phone != value)
{
phone = value;
OnPropertyChanged("Phone");
}
}
}
}
Usage:
var xx = new ClientModel();
xx.FirstName = "John";
xx.LastName = "Smith";
xx.DateOfBirth = DateTime.Now;
var result = xx.Serialize();
Result:
http://www.w3.org/2001/XMLSchema-instance\"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">
John Smith
2016-07-11T00:00:00+02:00
EDIT:
This code:
public void Execute(object param)
{
ClientViewModel viewModel = (ClientViewModel)param;
//TODO: Insert XML serialization and save to a file
var xml = Helper.Serialize(param);
//Placeholder to make sure the button works
viewModel.DisplayMessage = "You clicked the button at " + DateTime.Now;
}
Should be replaced by this:
public void Execute(object param)
{
ClientModel model= (ClientModel )param;
//TODO: Insert XML serialization and save to a file
var xml = Helper.Serialize(param);
//Placeholder to make sure the button works
viewModel.DisplayMessage = "You clicked the button at " + DateTime.Now;
}
Make sure, your Param is of type ClientModel.
I also highly recommend you, to get into the basics of how DataBinding works
Edit 2 (The Command-Thingy):
class Save : ICommand
{
public ClientModel Model { get; set; }
public bool CanExecute(object param) { return true; }
public event EventHandler CanExecuteChanged; //Compiler yells at you if you don't implement this from inhereted ICommand
public void Execute(object param)
{
//TODO: Insert XML serialization and save to a file
var xml = Helper.Serialize(this.Model);
//Placeholder to make sure the button works
viewModel.DisplayMessage = "You clicked the button at " + DateTime.Now;
}
}
Usage:
public ICommand SaveCommand
{
get
{
if (btnSave == null)
btnSave = new Save();
btnSave.Model = this.ClientModel;
return btnSave;
}
set { btnSave = value; }
}
I have a JSON class which I used to deserialize my object to :-
public class Response
{
private Meta _meta;
private Result _result;
private Output _output;
public Meta meta
{
set
{
if (this._meta == null)
{
this._meta = new Meta();
}
this._meta = value;
}
get
{
return this._meta;
}
}
public Output output
{
set
{
if (this._output == null)
{
this._output = new Output();
}
this._output = value;
}
get
{
return this._output;
}
}
}
Which inherit
public class Output
{
...
public Verified verified{
get
{
return this._verified;
}
set
{
if (this._verified == null)
{
this._verified = new Verified();
}
this._verified = value;
}
}
in which has sub class of
public class Verified
{
...
public Address Address
{
set
{
if (this.address == null)
{
this.address = new Address();
}
this.address = value;
}
get
{
return this.address;
}
}
public Age Age
{
get
{
return this.age;
}
set
{
if (this.age == null)
{
this.age = new Age();
}
this.age = value;
}
}
public City City
{
get
{
return this.city;
}
set
{
if (this.city == null)
{
this.city = new City();
}
this.city = value;
}
}
...
All the attribute in City, Age, and Address are the same such as
public class Address
{
public int code { get; set; }
public string text { get; set; }
}
I have manage to count how many attribute in the Verified by using
TotalQuestion = response.output.verified.GetType().GetProperties()
.Where(p => !p.PropertyType.IsGenericType
&& !p.PropertyType.IsArray)
.Count();
, and that is only half of my concern. I have to also count now many of the attribute "code" in each of the class in Address, City, Age which has value as 3.
I did tried to add .GetType().GetProperty("code") at the back of the same LinQ I used to query the total amount of question inside, but I got lost in mind how to complete it.
I hope that anyone would be able to advice on possible LinQ solution (hopefully one-liner) type.
Thanks.
Simon
I think this is what you are looking for -
var result = resp.output.verified.GetType().GetProperties().Where(
child => {
var prop = child.GetValue(resp.output.verified, null);
return (int)prop.GetType().GetProperty("code").GetValue(prop, null) == 3;
}).ToList();
I have a customer object class:
public class customerObject
{
private string _address1;
private string _address2;
private string _address3;
private string _category;
private string _country;
private string _county;
private string _custcode;
private string _fullname;
private string _int_rep_hou;
private string _int_rep_key;
private double _lat;
private double _lng;
private string _postcode;
private string _rep_code;
private string _telephone;
public customerObject()
{
}
public string Address1
{
get { return _address1; }
set { _address1 = value; }
}
public string Address2
{
get
{
return _address2;
}
set { _address2 = value; }
}
public string Address3 { get { return _address3; } set { _address3 = value; } }
public string Category
{
get { return _category; }
set { _category = value; }
}
public string Country { get { return _country; } set { _country = value; } }
public string County { get { return _county; } set { _county = value; } }
public string Custcode
{
get { return _custcode; }
set { _custcode = value; }
}
public string Fullname
{
get { return _fullname; }
set { _fullname = value; }
}
public string Int_rep_hou
{
get { return _int_rep_hou; }
set { _int_rep_hou = value; }
}
public string Int_rep_key
{
get { return _int_rep_key; }
set { _int_rep_key = value; }
}
public double Lat { get { return _lat; } set { _lat = value; } }
public double Lng { get { return _lng; } set { _lng = value; } }
public string Postcode { get { return _postcode; } set { _postcode = value; } }
public string Rep_code
{
get { return _rep_code; }
set { Rep_code = value; }
}
public string Telephone { get { return _telephone; } set { _telephone = value; }
}
}
I have a CustomCollections class
public class CustomerCollection
{
public List<customerObject> Customers { get; set; }
}
My method that loops through dt rows and converts to a customer object
public List<Valueobjects.CustomerCollection> dolist(DataTable temptablename)
{
//Create Collection Object
Valueobjects.CustomerCollection Collection = new Valueobjects.CustomerCollection();
foreach (DataRow row in temptablename.Rows)
{
//Create Customer Object
Valueobjects.customerObject Customer = new Valueobjects.customerObject();
//set values of customer object
Customer.Rep_code = "";
Customer.Int_rep_key = "";
Customer.Int_rep_hou = "";
Customer.Fullname = row["Fullname"].ToString().Trim();
Customer.Custcode = row["Custcode"].ToString().Trim();
Customer.Category = row["Category"].ToString().Trim();
Customer.Address1 = row["Address1"].ToString().Trim();
Customer.Address2 = row["Address2"].ToString().Trim();
Customer.Address3 = row["Address3"].ToString().Trim();
Customer.Postcode = row["Postcode"].ToString().Trim();
Customer.Country = row["Country"].ToString().Trim();
Customer.Telephone = row["Telephone"].ToString().Trim();
Customer.Lat = Convert.ToDouble(row["Lat"]);
Customer.Lng = Convert.ToDouble(row["Lng"]);
Customer.County = row["County"].ToString().Trim();
//add to the collection (list)
Collection.Customers.Add(Customer);
}
temptablename = null;
return Collection;
}
However when I create a new Customer object and a new CustomerCollection object I am getting an error when adding the customer to the collection list.
Error:
Error 32 Cannot implicitly convert type
'Classes.Valueobjects.CustomerCollection' to
'System.Collections.Generic.List'
Your method is returning a List<CustomerCollection>:
public List<Valueobjects.CustomerCollection> dolist(DataTable temptablename)
{
//...
}
But the code is trying to return a CustomerCollection:
return Collection;
Just as the error says, these two types are different.
If a CustomerCollection is already a collection of customers, then semantically what is a List<Valueobjects.CustomerCollection>? A collection of collections? It seems like you're over-pluralizing your objects :)
There are two approaches here. Either return a CustomerCollection from the method:
public CustomerCollection dolist(DataTable temptablename)
{
//...
}
Or use a List<Customer> if you want to use generic lists as your collection containers:
public List<Customer> dolist(DataTable temptablename)
{
//...
var Collection = new List<Customer>();
//...
Collection.Add(Customer);
//...
return Collection;
}
Side note: You may want to stick to C# conventions for variable naming. As you can see from the code highlighting here on Stack Overflow, your variable names can easily be mistaken for classes/types, which can cause confusion when supporting the code.
Return a CustomerCollection instead of a List<Valueobjects.CustomerCollection>:
public Valueobjects.CustomerCollection Dolist(DataTable temptablename)
{
// ...
Your object has a list, it is not a list.
MSDN: Inheritance
I've been trying for hours to get many-to-many relationship to save with Castle ActiveRecord. What am I doing wrong? I can't find anything in the documentation or on google. There is data in the database.
Courses have a many to many relationship with Books.
Test code.
Database.Course c = new Database.Course();
c.Number = "CS 433";
c.Name = "Databases";
c.Size = 34;
c.Books = Database.Book.FindAll();
c.Save();
Also doesn't work
foreach(Database.Book b in Database.Book.FindAll()){
c.Books.Add(b);
}
Database Classes
[ActiveRecord]
public class Course : ActiveRecordValidationBase<Course>
{
private int? id;
private string number;
private string name;
private string description;
private int size; //number of students in class
//references
private IList books = new ArrayList();
public override string ToString()
{
return FormattedName;
}
public string FormattedName
{
get
{
return string.Format("{0} - {1}", Number, Name);
}
}
[PrimaryKey]
public int? Id
{
get { return id; }
set { id = value; }
}
[Property, ValidateNonEmpty]
public string Number
{
get { return number; }
set { number = value; }
}
[Property, ValidateNonEmpty]
public string Name
{
get { return name; }
set { name = value; }
}
[Property(ColumnType="StringClob")]
public string Description
{
get { return description; }
set { description = value; }
}
[Property]
public int Size
{
get { return size; }
set { size = value; }
}
[HasAndBelongsToMany(typeof(Book),
Table = "BookCourse", ColumnKey = "course_id", ColumnRef = "book_id", Inverse = true)]
public IList Books
{
get { return books; }
set { books = value; }
}
}
[ActiveRecord]
public class Book : ActiveRecordValidationBase<Book>
{
private int? id;
private string title;
private string edition;
private string isbn;
private bool is_available_for_order;
//relations
private IList authors = new ArrayList();
private IList bookordercount = new ArrayList();
private IList courses = new ArrayList();
private Inventory inventory;
public override string ToString()
{
return FormattedName;
}
public string FormattedName
{
//*
get {
string str;
if (Edition == null || Edition == "")
str = Title;
else
str = string.Format("{0} ({1})", Title, Edition);
if (Authors.Count != 0)
{
return string.Format("{0} by {1}", str, FormattedAuthors);
}
else
{
return str;
}
}
/*/
get
{
return Title;
}
//*/
}
public string FormattedAuthors
{
get
{
if (Authors.Count == 0) return "";
StringBuilder sb = new StringBuilder();
int i = 0, end = Authors.Count;
foreach (Author a in Authors)
{
i++;
sb.Append(a.FormattedName);
if (i != end) sb.Append("; ");
}
return sb.ToString();
}
}
[PrimaryKey]
public int? Id
{
get { return id; }
set { id = value; }
}
[Property, ValidateNonEmpty]
public string Title
{
get { return title; }
set { title = value; }
}
[Property]
public string Edition
{
get { return edition; }
set { edition = value; }
}
[Property, ValidateNonEmpty]
public string Isbn
{
get { return isbn; }
set { isbn = value; }
}
[Property]
public bool IsAvailableForOrder
{
get { return is_available_for_order; }
set { is_available_for_order = value; }
}
//relations
[HasAndBelongsToMany(typeof(Author),
Table = "BookAuthor", ColumnKey = "book_id", ColumnRef = "author_id")]
public IList Authors
{
get { return authors; }
set { authors = value; }
}
[HasMany(typeof(BookOrderCount), Table = "BookOrderCounts", ColumnKey = "BookId")]
public IList BookOrderCount
{
get { return bookordercount; }
set { bookordercount = value; }
}
[HasAndBelongsToMany(typeof(Course),
Table = "BookCourse", ColumnKey = "book_id", ColumnRef = "course_id")]
public IList Courses
{
get { return courses; }
set { courses = value; }
}
[OneToOne]
public Inventory Inventory
{
get { return inventory; }
set { inventory = value; }
}
}
Make sure you put the Inverse = true where you want it. From the Castle AR docs,
It is wise to choose one side of the
relation as the owner. The other side,
the non-writable, need to use
Inverse=true.
Put the Inverse = true on the other side of the relationship, like this:
[HasAndBelongsToMany(typeof(Book),
Table = "BookCourse", ColumnKey = "course_id", ColumnRef = "book_id")]
public IList<Book> Books
[HasAndBelongsToMany(typeof(Course),
Table = "BookCourse", ColumnKey = "book_id", ColumnRef = "course_id", Inverse = true)]
public IList<Course> Courses
You also have to add attributes to the top of both classes - at the moment they don't know what tables they're mapped to. Currently you have this:
public class Course : ActiveRecordBase<Course>
Add this (where "course" is the name of your Course table):
[ActiveRecord("course")]
public class Course : ActiveRecordBase<Course>