/// Doing so has several advantages: /// /// - All strings prone to typos (bean kind and field names) are encapsulated inside. /// - You get compile-time checks, IDE assistance and [typed properties](#typed-accessors). /// - With [Lifecycle Hooks](#lifecycle-hooks), it is easy to implement [data validation](#data-validation) and [relations](#relations). /// /// For [Custom Beans Classes](#custom-bean-classes), use method overloads with a generic parameter: /// void Overloads(BeanApi api) { #if CODE api.Dispense <Book>(); api.Load <Book>(1); api.Find <Book>("WHERE rating > {0}", 7); // and so on #endif }
public void NotIsNewBean() { _storage.EnterFluidMode(); var key = _storage.Store("foo", SharedChecks.MakeRow("a", 1)); var foo = _api.Load("foo", key); Assert.False(_storage.IsNew(foo)); }
public DirtyTrackingTests() { _api = SQLitePortability.CreateApi(); _api.Exec("create table foo(id, a, b)"); _api.Exec("insert into foo values(1, 'initial', 'initial')"); _bean = _api.Load("foo", 1); _api.QueryExecuting += cmd => _queryCount++; }
void CRUD(BeanApi api) { /// ## Getting Started: Basic CRUD (Create/Read/Update/Delete) /// /// For basic usage, LimeBean requires no configuration or table classes! /// /// Take a look at some basic CRUD scenarios: /// /// **Create** #if CODE // Create a Bean. // "Bean" means row, and "Dispense" makes an empty Bean for a table. var bean = api.Dispense("book"); // Each bean has a "Kind". Kind is a synonym for "table name" // You give a Bean its Kind when you Dispense it, or query the database var kind = bean.GetKind(); Console.WriteLine(kind); // Fill the new Bean with some data bean["title"] = "Three Comrades"; bean["rating"] = 10; // You can also chain .Put() to do this bean.Put("title", "Three Comrades") .Put("rating", 10); // Store it // Store() will Create or Update a record intelligently var id = api.Store(bean); // Store also returns the Primary Key for the saved Bean, even for multi-column/compound keys Console.WriteLine(id); #endif /// **Read** and **Update** #if CODE // Load a Bean with a known ID bean = api.Load("book", id); // Make some edits bean["release_date"] = new DateTime(2015, 7, 30); bean["rating"] = 5; // Update database api.Store(bean); #endif /// **Delete** #if CODE api.Trash(bean); #endif }
public void Assigned_FrozenMode() { _api.Exec("create table foo (pk, prop)"); _api.Key("foo", "pk", false); var bean = _api.Dispense("foo"); bean["pk"] = "pk1"; bean["prop"] = "value1"; var key = _api.Store(bean); Assert.Equal("pk1", key); bean["prop"] = "value2"; Assert.Equal(key, _api.Store(bean)); bean = _api.Load("foo", key); Assert.Equal(key, bean["pk"]); Assert.Equal("value2", bean["prop"]); _api.Trash(bean); Assert.Equal(0, _api.Count("foo")); }
public void Scenario() { // Tell about your database var r = new BeanApi("data source=:memory:", SQLiteFactory.Instance); // Enable automatic schema update r.EnterFluidMode(); // create a bean var bean = r.Dispense("person"); // it's of kind "person" Console.WriteLine(bean.GetKind()); // give me the Id of the newly stored bean var id = bean // fill it .Put("name", "Alex") .Put("year", 1984) .Put("smart", true) // store it .Store(); // Database schema will be updated automatically for you // Now the bean has an id Console.WriteLine(bean["id"]); // load a bean bean = r.Load("person", id); bean // change it .Put("name", "Lexa") .Put("new_prop", 123) // commit changes .Store(); // or delete it r.Trash(bean); // close the connection r.Dispose(); }
void FluidMode(BeanApi api) { /// ## Fluid Mode /// LimeBean mitigates the common inconvenience associated with relational databases, /// namely necessity to manually create tables, columns and adjust their data types. /// In this sense, LimeBean takes SQL databases a little closer to NoSQL ones like MongoDB. /// /// **Fluid Mode** is optional, turned off by default, and is recommended for use only during early development stages /// (particularly for prototyping and scaffolding). /// To enable it, invoke the `EnterFluidMode` method on the `BeanApi` object: #if CODE api.EnterFluidMode(); // Make a Bean for a table which doesn't yet exist var bean = api.Dispense("book_types"); // Fill it with some data // Limebean will automatically detect Types and create columns with the correct Type bean.Put("name", "War") .Put("fiction", true); // Store will automatically create any missing tables (with an auto-incrementing 'id' column) and columns, // then add the Bean as a new row var id = api.Store(bean); // The bean is now available in the database var savedBean = api.Load("book_types", id); #endif /// How does this work? When you save a Bean while in Fluid Mode, LimeBean analyzes its fields and compares /// their names and types to the database schema. /// If new data cannot be stored to an existing table, schema alteration occurs. /// LimeBean can create new tables, add missing columns, and widen data types. /// It will never truncate data or delete unused columns. /// /// **NOTE:** LimeBean will not detect renamings. /// /// **CAUTION:** Automatically generated schema is usually sub-optimal and lacks indexes which are essential /// for performance. When most planned tables are already in place, /// it is recommended you turn Fluid Mode off, audit the database structure, add indexes, and make further schema /// changes with a dedicated database management tool (like HeidiSQL, SSMS, pgAdmin, etc). /// }
/// <summary> /// Gets the owner Bean (the "1"-side of a 1:n relation. /// If the Foreign Key Name of the (owned) Bean differs form the /// Name of the Owner Bean, it is possible to pass an alias name. /// </summary> /// <param name="ownerKind">Kind of the owner Bean.</param> /// <param name="fkAlias">Alias for the Owner Bean's Foreign Key Name (w/o Primary Key Name)</param> /// <returns>Owner Bean</returns> public Bean GetOwner(string ownerKind, string fkAlias = "") { var foreignKey = GetFkName(fkAlias == string.Empty ? ownerKind : fkAlias); return(Api.Load(ownerKind, _props[foreignKey])); }
void CRUD() { /// ## CRUD /// (Create / Read / Update / Delete) /// /// For basic usage, LimeBean requires zero configuration and no additional code! /// Database schema is maintained on-the-fly: /// no need to create tables and columns (see [Fluid Mode](#fluid-mode)). /// /// Take a look at the following sample scenario: /// #if CODE // Use a temporary in-memory SQLite database var api = new BeanApi("Data Source=:memory:", SQLiteFactory.Instance); // Enter the "Fluid Mode" api.EnterFluidMode(); #endif /// **Create** #if CODE // Create a bean. "Bean" means "data record", "dispense" means "instantiate new". var bean = api.Dispense("book"); // Each bean has a kind. "Kind" is a synonym for "table name" var kind = bean.GetKind(); Console.WriteLine(kind); // Fill it with some data bean["title"] = "Three Comrades"; bean["rating"] = 10; // Store it // Table "book" with 2 columns, one string and one integer, will be generated automatically var id = api.Store(bean); // Each saved bean has an ID, or primary key Console.WriteLine(id); #endif /// **Read** #if CODE // Load by ID bean = api.Load("book", id); #endif /// **Update** #if CODE // Make some edits bean["title"] = "Learn LimeBean"; bean["release_date"] = new DateTime(2015, 7, 30); bean["rating"] = "good"; // Save updated bean // One new column ("release_date") will be added // The type of column "rating" will be expanded from integer to string api.Store(bean); #endif /// **Delete** #if CODE api.Trash(bean); // Don't forget to close the connection api.Dispose(); #endif }
/// Doing so has several advantages: /// /// - All strings prone to typos (bean kind and field names) are encapsulated inside. /// - You get compile-time checks, IDE assistance and [typed properties](#typed-accessors). /// - With [Lifecycle Hooks](#lifecycle-hooks), it is easy to implement [data validation](#data-validation) and [relations](#relations). /// /// For [Custom Beans Classes](#custom-bean-classes), use method overloads with a generic parameter: /// void Overloads(BeanApi api) { #if CODE api.Dispense<Book>(); api.Load<Book>(1); api.Find<Book>("WHERE rating > {0}", 7); // and so on #endif }
public void AttachesBean() { _api.Exec("CREATE TABLE Bean1 (id, Prop)"); _api.Exec("INSERT INTO Bean1 VALUES(1, 'Bean1Prop')"); _api.Exec("CREATE TABLE Bean4 (id, Bean1_id, Prop)"); _api.Exec("INSERT INTO Bean4 VALUES (1, null, 'Bean4Prop1')"); var bean1 = _api.Load("Bean1", 1); // existing Bean var bean41 = _api.Load("Bean4", 1); // new Bean var bean42 = _api.Dispense("Bean4").Put("Prop", "Bean4Prop2"); Assert.True(bean1.AttachOwned(bean41)); Assert.True(bean1.AttachOwned(bean42)); var ownedBeans = bean1.GetOwnedList("Bean4"); var cOwnedBeans = bean1.GetOwnedList <Bean4>(); Assert.Equal(2, ownedBeans.Count); Assert.Equal(2, cOwnedBeans.Count); Assert.Equal("Bean4Prop1", ownedBeans[0]["Prop"]); Assert.Equal("Bean4Prop2", ownedBeans[1]["Prop"]); Assert.Equal("Bean4Prop1", cOwnedBeans[0]["Prop"]); Assert.Equal("Bean4Prop2", cOwnedBeans[1]["Prop"]); // Attaching with missing FK in referencing Bean Assert.Throws <MissingForeignKeyColumnException>(() => bean41.AttachOwned(bean1)); }