Skip to content

Commit 15a79cf

Browse files
committed
update latest OrmLite README in /docs
1 parent cef545c commit 15a79cf

File tree

2 files changed

+308
-12
lines changed

2 files changed

+308
-12
lines changed

lib/ServiceStack.XML

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Docs/ormlite/ormlite-overview.md

Lines changed: 303 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,324 @@ for twitter updates.
55
ServiceStack.OrmLite is a convention-based, configuration-free lightweight ORM that uses standard POCO classes and Data Annotation attributes to infer its table schema.
66
# Introduction
77

8-
OrmLite is a set of light-weight C# extension methods around System.Data.`*` interfaces which is designed to persist POCO classes with a minimal amount of intrusion and configuration.
8+
OrmLite is a set of light-weight C# extension methods around `System.Data.*` interfaces which is designed to persist POCO classes with a minimal amount of intrusion and configuration.
99
Another Orm with similar goals is [sqlite-net](http://code.google.com/p/sqlite-net/).
1010

11-
OrmLite was designed with a focus on these core objectives:
11+
OrmLite was designed with a focus on the core objectives:
1212

13-
* Simplicity - with minimal, convention-based attribute configuration
13+
* Map a POCO class 1:1 to an RDBMS table, cleanly by conventions, without any attributes required.
14+
* Create/Drop DB Table schemas using nothing but POCO class definitions (IOTW a true code-first ORM)
15+
* Simplicity - typed, wrist friendly API for common data access patterns.
1416
* High performance - with support for indexes, text blobs, etc.
17+
* Amongst the [fastest Micro ORMs](http://servicestack.net/benchmarks/) for .NET (just behind [Dapper](http://code.google.com/p/dapper-dot-net/)).
1518
* Expressive power and flexibility - with access to IDbCommand and raw SQL
1619
* Cross platform - supports multiple dbs (currently: Sqlite and Sql Server) running on both .NET and Mono platforms.
1720

21+
In OrmLite: **1 Class = 1 Table**. There's no hidden behaviour behind the scenes auto-magically managing hidden references to other tables.
22+
Any non-scalar properties (i.e. complex types) are text blobbed in a schema-less text field using [.NET's fastest Text Serializer](http://www.servicestack.net/mythz_blog/?p=176).
23+
Effectively this allows you to create a table from any POCO type and it should persist as expected in a DB Table with columns for each of the classes 1st level public properties.
24+
25+
### Other notable Micro ORMs for .NET
26+
Many performance problems can be mitigated and a lot of use-cases can be simplified without the use of a heavyweight ORM, and their config, mappings and infrastructure.
27+
As [performance is the most important feature](https://github.com/mythz/ScalingDotNET) we can recommend the following list, each with their own unique special blend of features.
28+
29+
* **[Dapper](http://code.google.com/p/dapper-dot-net/)** - by [@samsaffron](http://twitter.com/samsaffron) and [@marcgravell](http://twitter.com/marcgravell)
30+
- The current performance king, supports both POCO and dynamic access, fits in a single class. Put in production to solve [StackOverflow's DB Perf issues](http://samsaffron.com/archive/2011/03/30/How+I+learned+to+stop+worrying+and+write+my+own+ORM). Requires .NET 4.
31+
* **[PetaPoco](http://www.toptensoftware.com/petapoco/)** - by [@toptensoftware](http://twitter.com/toptensoftware)
32+
- Fast, supports dynamics, expandos and typed POCOs, fits in a single class, runs on .NET 3.5 and Mono. Includes optional T4 templates for POCO table generation.
33+
* **[Massive](https://github.com/robconery/massive)** - by [@robconery](http://twitter.com/robconery)
34+
- Fast, supports dynamics and expandos, smart use of optional params to provide a wrist-friendly api, fits in a single class. Multiple RDBMS support. Requires .NET 4.
35+
* **[Simple.Data](https://github.com/markrendle/Simple.Data)** - by [@markrendle](http://twitter.com/markrendle)
36+
- A little slower than above ORMS, most wrist-friendly courtesy of a dynamic API, multiple RDBMS support inc. Mongo DB. Requires .NET 4.
37+
1838
# Download
19-
OrmLite is included with [ServiceStack.zip](https://github.com/downloads/mythz/ServiceStack/ServiceStack.zip) or available to download separately in a standalone
20-
[ ServiceStack.OrmLite.zip](https://github.com/downloads/mythz/ServiceStack.OrmLite/ServiceStack.OrmLite.zip).
2139

22-
The full source code for OrmLite is also [available online](~/ormlite/ormlite-overview).
40+
[![Download on NuGet](http://www.servicestack.net/img/nuget-servicestack.ormlite.sqlserver.png)](http://nuget.org/List/Packages/ServiceStack.OrmLite.SqlServer)
41+
42+
You can download OrmLite on NuGet in 3 flavours:
43+
[Sql Server](http://nuget.org/List/Packages/ServiceStack.OrmLite.SqlServer),
44+
[Sqlite32](http://nuget.org/List/Packages/ServiceStack.OrmLite.Sqlite32) and
45+
[Sqlite64](http://nuget.org/List/Packages/ServiceStack.OrmLite.Sqlite64).
46+
47+
OrmLite is also included in [ServiceStack](https://github.com/ServiceStack/ServiceStack/downloads) or available to download separately in
48+
[/downloads](https://github.com/ServiceStack/ServiceStack.OrmLite/downloads).
49+
50+
51+
52+
# Code-first Customer & Order example with complex types on POCO as text blobs
53+
54+
Below is a complete stand-alone example. No other config or classes is required for it to run. It's also available as a
55+
[stand-alone unit test](https://github.com/ServiceStack/ServiceStack.OrmLite/blob/master/tests/ServiceStack.OrmLite.Tests/UseCase/CustomerOrdersUseCase.cs).
56+
57+
public enum PhoneType {
58+
Home,
59+
Work,
60+
Mobile,
61+
}
62+
63+
public enum AddressType {
64+
Home,
65+
Work,
66+
Other,
67+
}
68+
69+
public class Address {
70+
public string Line1 { get; set; }
71+
public string Line2 { get; set; }
72+
public string ZipCode { get; set; }
73+
public string State { get; set; }
74+
public string City { get; set; }
75+
public string Country { get; set; }
76+
}
77+
78+
public class Customer {
79+
public Customer() {
80+
this.PhoneNumbers = new Dictionary<PhoneType, string>();
81+
this.Addresses = new Dictionary<AddressType, Address>();
82+
}
83+
84+
[AutoIncrement] // Creates Auto primary key
85+
public int Id { get; set; }
86+
87+
public string FirstName { get; set; }
88+
public string LastName { get; set; }
89+
90+
[Index(Unique = true)] // Creates Unique Index
91+
public string Email { get; set; }
92+
93+
public Dictionary<PhoneType, string> PhoneNumbers { get; private set; } //Blobbed
94+
public Dictionary<AddressType, Address> Addresses { get; private set; } //Blobbed
95+
public DateTime CreatedAt { get; set; }
96+
}
97+
98+
public class Order {
99+
100+
[AutoIncrement]
101+
public int Id { get; set; }
102+
103+
[References(typeof(Customer))] //Creates Foreign Key
104+
public int CustomerId { get; set; }
105+
106+
[References(typeof(Employee))] //Creates Foreign Key
107+
public int EmployeeId { get; set; }
108+
109+
public Address ShippingAddress { get; set; } //Blobbed (no Address table)
110+
111+
public DateTime? OrderDate { get; set; }
112+
public DateTime? RequiredDate { get; set; }
113+
public DateTime? ShippedDate { get; set; }
114+
public int? ShipVia { get; set; }
115+
public decimal Freight { get; set; }
116+
public decimal Total { get; set; }
117+
}
118+
119+
public class OrderDetail {
120+
121+
[AutoIncrement]
122+
public int Id { get; set; }
123+
124+
[References(typeof(Order))] //Creates Foreign Key
125+
public int OrderId { get; set; }
126+
127+
public int ProductId { get; set; }
128+
public decimal UnitPrice { get; set; }
129+
public short Quantity { get; set; }
130+
public decimal Discount { get; set; }
131+
}
132+
133+
public class Employee {
134+
public int Id { get; set; }
135+
public string Name { get; set; }
136+
}
137+
138+
public class Product {
139+
public int Id { get; set; }
140+
public string Name { get; set; }
141+
public decimal UnitPrice { get; set; }
142+
}
143+
144+
//Setup SQL Server Connection Factory
145+
var dbFactory = new OrmLiteConnectionFactory(
146+
@"Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\App_Data\Database1.mdf;Integrated Security=True;User Instance=True",
147+
SqlServerOrmLiteDialectProvider.Instance);
148+
149+
//Use in-memory Sqlite DB instead
150+
//var dbFactory = new OrmLiteConnectionFactory(
151+
// ":memory:", false, SqliteOrmLiteDialectProvider.Instance);
152+
153+
//Non-intrusive: All extension methods hang off System.Data.* interfaces
154+
IDbConnection dbConn = dbFactory.OpenDbConnection();
155+
IDbCommand dbCmd = dbConn.CreateCommand();
156+
157+
//Re-Create all table schemas:
158+
dbCmd.DropTable<OrderDetail>();
159+
dbCmd.DropTable<Order>();
160+
dbCmd.DropTable<Customer>();
161+
dbCmd.DropTable<Product>();
162+
dbCmd.DropTable<Employee>();
163+
164+
dbCmd.CreateTable<Employee>();
165+
dbCmd.CreateTable<Product>();
166+
dbCmd.CreateTable<Customer>();
167+
dbCmd.CreateTable<Order>();
168+
dbCmd.CreateTable<OrderDetail>();
169+
170+
dbCmd.Insert(new Employee { Id = 1, Name = "Employee 1" });
171+
dbCmd.Insert(new Employee { Id = 2, Name = "Employee 2" });
172+
var product1 = new Product { Id = 1, Name = "Product 1", UnitPrice = 10 };
173+
var product2 = new Product { Id = 2, Name = "Product 2", UnitPrice = 20 };
174+
dbCmd.Save(product1, product2);
175+
176+
var customer = new Customer
177+
{
178+
FirstName = "Orm",
179+
LastName = "Lite",
180+
Email = "[email protected]",
181+
PhoneNumbers =
182+
{
183+
{ PhoneType.Home, "555-1234" },
184+
{ PhoneType.Work, "1-800-1234" },
185+
{ PhoneType.Mobile, "818-123-4567" },
186+
},
187+
Addresses =
188+
{
189+
{ AddressType.Work, new Address { Line1 = "1 Street", Country = "US", State = "NY", City = "New York", ZipCode = "10101" } },
190+
},
191+
CreatedAt = DateTime.UtcNow,
192+
};
193+
dbCmd.Insert(customer);
194+
195+
var customerId = dbCmd.GetLastInsertId(); //Get Auto Inserted Id
196+
customer = dbCmd.QuerySingle<Customer>(new { customer.Email }); //Query
197+
Assert.That(customer.Id, Is.EqualTo(customerId));
198+
199+
//Direct access to System.Data.Transactions:
200+
using (var trans = dbCmd.BeginTransaction(IsolationLevel.ReadCommitted))
201+
{
202+
var order = new Order
203+
{
204+
CustomerId = customer.Id,
205+
EmployeeId = 1,
206+
OrderDate = DateTime.UtcNow,
207+
Freight = 10.50m,
208+
ShippingAddress = new Address { Line1 = "3 Street", Country = "US", State = "NY", City = "New York", ZipCode = "12121" },
209+
};
210+
dbCmd.Save(order); //Inserts 1st time
211+
212+
order.Id = (int)dbCmd.GetLastInsertId(); //Get Auto Inserted Id
213+
214+
var orderDetails = new[] {
215+
new OrderDetail
216+
{
217+
OrderId = order.Id,
218+
ProductId = product1.Id,
219+
Quantity = 2,
220+
UnitPrice = product1.UnitPrice,
221+
},
222+
new OrderDetail
223+
{
224+
OrderId = order.Id,
225+
ProductId = product2.Id,
226+
Quantity = 2,
227+
UnitPrice = product2.UnitPrice,
228+
Discount = .15m,
229+
}
230+
};
231+
232+
dbCmd.Insert(orderDetails);
233+
234+
order.Total = orderDetails.Sum(x => x.UnitPrice * x.Quantity * x.Discount) + order.Freight;
235+
236+
dbCmd.Save(order); //Updates 2nd Time
237+
238+
trans.Commit();
239+
}
240+
241+
Running this against a SQL Server database will yield the results below:
242+
243+
[![SQL Server Management Studio results](http://www.servicestack.net/files/ormlite-example.png)](http://www.servicestack.net/files/ormlite-example.png)
244+
245+
Notice the POCO types are stored in the [very fast](http://www.servicestack.net/mythz_blog/?p=176)
246+
and [Versatile](http://www.servicestack.net/mythz_blog/?p=314)
247+
[JSV Format](https://github.com/ServiceStack/ServiceStack.Text/wiki/JSV-Format) which although hard to do -
248+
is actually more compact, human and parser-friendly than JSON :)
249+
250+
# API Overview
251+
252+
The API is minimal, providing basic shortcuts for the primitive SQL statements:
253+
254+
[![OrmLite API](http://www.servicestack.net/files/ormlite-api.png)](http://www.servicestack.net/files/ormlite-api.png)
255+
256+
Nearly all extension methods hang off the implementation agnostic `IDbCommand`.
257+
258+
`CreateTable<T>` and `DropTable<T>` create and drop tables based on a classes type definition (only public properties used).
259+
260+
For a one-time use of a connection, you can query straight of the `IDbFactory` with:
261+
262+
var customers = dbFactory.Exec(dbCmd => dbCmd.Where<Customer>(new { Age = 30 }));
263+
264+
The **Select** methods allow you to construct Sql using C# `string.Format()` syntax.
265+
If you're SQL doesn't start with a **SELECT** statement, it is assumed a WHERE clause is being provided, e.g:
266+
267+
var tracks = dbCmd.Select<Track>("Artist = {0} AND Album = {1}", "Nirvana", "Heart Shaped Box");
268+
269+
The same results could also be fetched with:
270+
271+
var tracks = dbCmd.Select<Track>("select * from track WHERE Artist = {0} AND Album = {1}", "Nirvana", "Heart Shaped Box");
272+
273+
**Select** returns multiple records
274+
275+
List<Track> tracks = dbCmd.Select<Track>()
276+
277+
**Single** returns a single record
278+
279+
Track track = dbCmd.Single<Track>("RefId = {0}", refId)
280+
281+
**GetDictionary** returns a Dictionary made from the first to columns
282+
283+
Dictionary<int,string> trackIdNamesMap = dbCmd.GetDictionary<int, string>("select Id, Name from Track")
284+
285+
**GetLookup** returns an `Dictionary<K, List<V>>` made from the first to columns
286+
287+
var albumTrackNames = dbCmd.GetLookup<int, string>("select AlbumId, Name from Track")
288+
289+
**GetFirstColumn** returns a List of first column values
290+
291+
List<string> trackNames = dbCmd.GetFirstColumn<string>("select Name from Track")
292+
293+
**GetScalar** returns a single scalar value
294+
295+
var trackCount = dbCmd.GetScalar<int>("select count(*) from Track")
296+
297+
All **Insert**, **Update**, and **Delete** methods take multiple params, while `InsertAll`, `UpdateAll` and `DeleteAll` take IEnumerables.
298+
**GetLastInsertId** returns the last inserted records auto incremented primary key.
299+
300+
`Save` and `SaveAll` will Insert if no record with **Id** exists, otherwise it Updates.
301+
Both take multiple items, optimized to perform a single read to check for existing records and are executed within a sinlge transaction.
302+
303+
Methods containing the word **Each** return an IEnumerable<T> and are lazily loaded (i.e. non-buffered).
304+
305+
Selection methods containing the word **Query** or **Where** use parameterized SQL (other selection methods do not).
306+
Anonymous types passed into **Where** are treated like an **AND** filter.
307+
308+
var track3 = dbCmd.Where<Track>(new { AlbumName = "Throwing Copper", TrackNo = 3 })
309+
310+
**Query** statements take in parameterized SQL using properties from the supplied anonymous type (if any)
311+
312+
var track3 = dbCmd.Query<Track>("select * from Track Where AlbumName = @album and TrackNo = @trackNo",
313+
new { album = "Throwing Copper", trackNo = 3 })
314+
315+
GetById(s), QueryById(s), etc provide strong-typed convenience methods to fetch by a Table's **Id** primary key field.
316+
317+
var track = dbCmd.QueryById<Track>(1);
318+
23319

24320
# Limitations
25321

26322
For simplicity, and to be able to have the same POCO class persisted in db4o, memcached, redis or on the filesystem (i.e. providers included in ServiceStack), each model must have an '`Id`' property which is its primary key.
27323

28324

29-
# Examples
325+
# More Examples
30326

31327
In its simplest useage, OrmLite can persist any POCO type without any attributes required:
32328

0 commit comments

Comments
 (0)