Skip to content

Commit

Permalink
Added in rough import of docs
Browse files Browse the repository at this point in the history
  • Loading branch information
subsonic committed Feb 1, 2014
1 parent fe468ac commit 6204492
Show file tree
Hide file tree
Showing 141 changed files with 3,274 additions and 48 deletions.
2 changes: 1 addition & 1 deletion _config.yml
Expand Up @@ -11,7 +11,7 @@ subscribe_rss: http://subsonic.github.io/atom.xml

# Github repositories
github_user: subsonic
github_repo_url: https://github.com/subsonic/SubSonic-3.0/
github_repo_url: https://github.com/subsonic/subsonic.github.io/

# Twitter
twitter_user: robconery
Expand Down
2 changes: 1 addition & 1 deletion _includes/header.html
@@ -1,4 +1,4 @@
<div style="margin-bottom: 32px">
<div style="margin-bottom: 32px;margin-top:240px">
<img src="http://media.wekeroad.com/SubSonicSMall.png" alt="">
</div>
<hgroup>
Expand Down
2 changes: 1 addition & 1 deletion _includes/navigation.html
@@ -1,6 +1,6 @@
<ul class="main-navigation">
<li><a href="/about/">about</a></li>
<li><a href="/archive">archives</a></li>
<li><a href="/archive">docs</a></li>
</ul>

{% if site.description %}
Expand Down
16 changes: 0 additions & 16 deletions _layouts/default.html
Expand Up @@ -14,19 +14,3 @@
<footer id="footer" class="inner">{% include footer.html %}</footer>
</div>
</div>


<!-- CodeProject AD -->
<script>
function _dmBootstrap(file) {
var _dma = document.createElement('script');
_dma.type = 'text/javascript';
_dma.async = true;
_dma.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + file;
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(_dma);
}
function _dmFollowup(file) { if (typeof DMAds === 'undefined') _dmBootstrap('cdn2.DeveloperMedia.com/a.min.js');}
(function () { _dmBootstrap('cdn1.DeveloperMedia.com/a.min.js'); setTimeout(_dmFollowup, 2000);})();
</script>
</body>
</html>
6 changes: 0 additions & 6 deletions _layouts/post.html
Expand Up @@ -27,9 +27,3 @@
</div>
</div>

{% if site.disqus_short_name and page.comments == true %}
<section id="comment">
<h1 class="title">Comments</h1>
<div id="disqus_thread" aria-live="polite">{% include post/disqus_thread.html %}</div>
</section>
{% endif %}
14 changes: 14 additions & 0 deletions _posts/2009-04-03-automating_subsonics_magic.markdown
@@ -0,0 +1,14 @@
---
layout: post
title: "Automating SubSonic's Magic"
---

# Automating SubSonic's Magic

Let's face it - it sucks to write XML and do any kind of configuration ... period. This is why we lean on Conventions, and if we all follow conventions, we can build on that to make some more magic happen. Magical Automation is fun.

<h2>Using the Build Provider</h2>

This will only work with Web Sites - it WILL NOT WORK with Web Applications or MVC.
. Install SubSonic as described in
and make sure to add a reference to the SubSonic DLL. Once that's completed, edit your Web.config to add the following line:<compilation debug="true" defaultLanguage="C#"> <buildProviders> <add extension=".abp" type="SubSonic.BuildProvider, SubSonic"/> </buildproviders> Next, create a file with the extension "abp" - you can put whatever you like in the file; it's not read and it doesn't matter. The only thing that matters is the file extension. Add this file to the App_Code directory. BAM. You now have a Data Access Layer.
8 changes: 8 additions & 0 deletions _posts/2009-04-03-descriptor.markdown
@@ -0,0 +1,8 @@
---
layout: post
title: "Descriptor"
---

# Descriptor

A "Descriptor" in SubSonic parlance is the first string value, no foreign-key field in a database. This value is *assumed* to be some type of descriptive value for the data in that row. Using a Product table as an analogy - the primary key would (normally) be the first field, the ProductName would be the second. SubSonic would consider ProductName to be the Descriptor and would use that for linking and display purposes.
12 changes: 12 additions & 0 deletions _posts/2009-04-03-inline_query_tool.markdown
@@ -0,0 +1,12 @@
---
layout: post
title: "Inline Query Tool"
---

# Inline Query Tool

Sometimes there's just no way an ORM can do what you want it to do, and I completely recognize this. It's just not a good idea to try to use your ORM for everything - and it's why I always say "SubSonic isn't really an ORM - it's a query tool". Given that, we want to give you a back door, and in honor of Jeff Atwood we created the Inline Query tool. Go ahead - no one's looking... do your job and be proud of it.public void Inline_Simple() { QueryCommand cmd = new InlineQuery().GetCommand("SELECT productID from products"); Assert.IsTrue(cmd.CommandSql

<h2> "SELECT productID from products"); } public void Inline_WithCommands() { QueryCommand cmd = new InlineQuery() .GetCommand(@"SELECT productID from products WHERE productid=@productid", 1); Assert.IsTrue(cmd.Parameters[0].ParameterName == "@productid"); Assert.IsTrue((int)cmd.Parameters[0].ParameterValue </h2>

1); } public void Inline_AsCollection() { ProductCollection products = new InlineQuery() .ExecuteAsCollection<ProductCollection>( @"SELECT productID from products WHERE productid=@productid", 1); }
28 changes: 28 additions & 0 deletions _posts/2009-04-03-linq_aggregate_queries.markdown
@@ -0,0 +1,28 @@
---
layout: post
title: "Linq Aggregate Queries"
---

# Linq Aggregate Queries



<h2>Summary== You can run aggregate queries using our Linq engine in the exact same way you do with Linq to Sql:[TestMethod] public void Aggregates_Should_Run_Count_Old_Skool() { decimal result = (decimal)_db.Products .Count(); Assert.IsTrue(result > 0); } [TestMethod] public void Aggregates_Should_Run_Avg_Old_Skool() { decimal result = (decimal)_db.Products .Average(x=>x.ProductID); Assert.IsTrue(result > 0); } [TestMethod] public void Aggregates_Should_Run_Sum_Old_Skool() { decimal result = (decimal)_db.Products .Sum(x => x.UnitPrice); Assert.IsTrue(result > 0); } As with all queries, if you try to get to deep into the analytics here you may end up in trouble. These are meant for the basic "80%" scenarios, where you need a sum/average/whatever. Ideally, the aggregate query you're trying to write will give you what you want to know. ==Rollup Queries</h2>

In this example we'll rollup a count of Products for each Category in Northwind - and it works just fine:
[TestMethod] public void Aggregates_Should_Run_Joined_Count_Old_Skool() { var result = from c in _db.Categories select new { Name = c.CategoryName, Count = _db.Products.Where(x => x.CategoryID == c.CategoryID).Count() }; Assert.AreEqual(8,result.Count()); Assert.AreEqual("Beverages", result.ToList()[0].Name); Assert.AreEqual(12, result.ToList()[0].Count); } This produces this SQL here:
SELECT [t0].[CategoryName], ( SELECT COUNT(*) FROM [dbo].[Products] AS t1 WHERE ([t1].[CategoryID] = [t0].[CategoryID]) ) AS c0 FROM [dbo].[Categories] AS t0 But do you see a weirdness in there on how the results could fail (aside from the fact that I'm hitting the live DB)? I'm not specifying an ORDER BY and therefore the Assert could fail if, for some reason, "Beverages" wasn't the first record (which could easily happen if we switched indexing around).

<h2>Failing Aggregate Query</h2>

I could alter the query to this:
var result = from c in _db.Categories orderby c.CategoryID select new { Name = c.CategoryName, Count = _db.Products.Where(x => x.CategoryID == c.CategoryID).Count() }; ... which would produce this SQL:
SELECT [t0].[CategoryName], ( SELECT COUNT(*) FROM [dbo].[Products] AS t1 WHERE ([t1].[CategoryID] = [t0].[CategoryID]) ) AS c0 FROM [dbo].[Categories] AS t0 ORDER BY [t0].[CategoryID] ... and boom, we have an issue. "CategoryID" is not included in the SELECT statement, so we have a problem and we get an error. Even if I include "CategoryID" in the projection, it still won't work.
This is a limitation of our parser and we're working on a fix. The point is - there are limitations (and yes, some of them are silly) and we're trying to get those fixed up. If you do run into a situation like this, you can always use our
to get around it.

<h2>Using The Query Surface Aggregates</h2>

The
- aka the "Data Context" defines aggregate queries for you straight away, and you can use them as "quickie" aggregate calls to the DB:
[TestMethod] public void Aggregates_Should_Return_Average() { decimal result = (decimal)_db.Avg<Product>(x => x.UnitPrice).ExecuteScalar(); Assert.IsTrue(result > 0); } [TestMethod] public void Aggregates_Should_Return_Max() { var result1 = (int)_db.Max<Product>(x => x.ProductID).ExecuteScalar(); Assert.AreEqual(result1, 77); var result2 = _db.Products.Max(x => x.ProductID); Assert.AreEqual(result1, result2); } [TestMethod] public void Aggregates_Should_Return_Min() { var result1 = (int)_db.Min<Product>(x => x.ProductID).ExecuteScalar(); Assert.AreEqual(result1, 1); var result2 = _db.Products.Min(x => x.ProductID); Assert.AreEqual(result1, result2); }
57 changes: 57 additions & 0 deletions _posts/2009-04-03-linq_select_queries.markdown
@@ -0,0 +1,57 @@
---
layout: post
title: "Linq Select Queries"
---

# Linq Select Queries



<h2>Summary</h2>

SubSonic 3.0 uses
as the primary option to query a database. You can perform a multitude of queries in this way, including
,
, and
.

<h2>Limitations</h2>

Linq is a C# language feature, NOT a database query language. As such we do our best to try and figure out what you want us to do. This won't always work and there will be times with the query is just plain too complex.
Important: SubSonic is not as complete as Linq to SQL in terms of Linq translation. Hopefully this will change someday - but if you run into a wall, you can always use our
.

<h2>Setup</h2>

In order to run the queries below, you'll need to generate your
and
by dropping the SubSonic
will fire up the templates and generate the stuff you need.

<h2>Example Code</h2>

If you don't know what Linq is or how to use it,
; var result = from p in _db.Products where p.CategoryID

<h2> categoryID select p; Assert.AreEqual(7, result.Count()); } [TestMethod] public void Select_Simple_With_Variable_And_Join() { int categoryID = 5; //create DB from QuerySurface, aka "DB" _db = DB.CreateDB(); var result = from p in _db.Products join c in _db.Categories on p.CategoryID equals c.CategoryID where p.CategoryID == categoryID select p; Assert.AreEqual(7, result.Count()); } [TestMethod] public void Select_Simple_With_ForeignKeys() { //create DB from QuerySurface, aka "DB" _db = DB.CreateDB(); Order o = _db.Orders.Where(x => x.OrderID == 10248) .SingleOrDefault(); Assert.AreEqual(3, o.OrderDetails.Count()); } == Joins </h2>

SubSonic supports most joins, but you should be aware that you can easily break this. Below is an example of a typical join query, and follows closely with that of Linq to Sql:
[TestMethod] public void Select_Using_Many_To_Many() { var db = DB.CreateDB(); var query = from e in db.Employees join et in db.EmployeeTerritories on e.EmployeeID equals et.EmployeeID join t in db.Territories on et.TerritoryID equals t.TerritoryID where e.EmployeeID

<h2> 1 select e; int count = query.Count(); Assert.AreEqual(2, count); Assert.AreEqual("Daviolo", query.ToList()[0].LastName); } [TestMethod] public void LINQ_Join_Query_Take1() { var results = from c in _db.Customers from o in _db.Orders from od in _db.OrderDetails where c.CustomerID == o.CustomerID && o.OrderID </h2>

od.OrderID select new { CustomerID = c.CustomerID, CompanyName = c.CompanyName, ShipAddress = o.ShipAddress, ShippedDate = o.ShippedDate, ProductID = od.ProductID, Quantity = od.Quantity }; Assert.AreEqual(2155, results.Count()); } The latter query here, while syntacticly correct, could possibly cause issues for you if we can't tell what equalities to join on (which could happen with many tables). This same query could be written this way, and would be a bit safer:
/// <summary> /// An other way to write the above query /// </summary> [TestMethod] public void LINQ_Join_Query_Take2() { var results = from c in _db.Customers join o in _db.Orders on c.CustomerID equals o.CustomerID join od in _db.OrderDetails on o.OrderID equals od.OrderID select new { CustomerID = c.CustomerID, CompanyName = c.CompanyName, ShipAddress = o.ShipAddress, ShippedDate = o.ShippedDate, ProductID = od.ProductID, Quantity = od.Quantity }; Assert.AreEqual(2155, results.Count()); }

<h2>Projecting Results</h2>

In the last query we used the construct "select new", which is an "Anonymous Type" according to C# - this means that we made the type up on the fly and shoved the query results into it. This can be handy for a number of situations - specifically if you're trying to return a simple result set, or if you need to pump the results into another type. This code snippet shows how you can project the results of a Select query into a new type, called "ProjectedProduct":
/// <summary> /// Dummy class for testing use /// </summary> public class ProjectedProduct { public string SKU { get; set; } public string Name { get; set; } } [TestMethod] public void LINQ_Query_Projection() { var db = DB.CreateDB(); var results = from p in db.Products select new ProjectedProduct { SKU=p.ProductID.ToString(), Name=p.ProductName.ToString() }; Assert.AreEqual(77, results.Count()); }

<h2>Failing Query Example</h2>


This has limitations. In our testing we've found that if more than one type is involved in this projection (using
let statements with a child collection for example) - it will fail. This is a known issue! For example, if we were to use this as our projection test:
/// <summary> /// Dummy class for testing use /// </summary> public class ProjectedProduct { public string SKU { get; set; } public string Name { get; set; } public IQueryable<ProjectedCategory> Categories { get; set; } } public class ProjectedCategory { public string Name { get; set; } } IQueryable<ProjectedCategory> GetCategories() { var db = DB.CreateDB(); return from c in db.Categories select new ProjectedCategory { Name=c.CategoryName }; } [TestMethod] public void LINQ_Query_Projection() { var db = DB.CreateDB(); var results = from p in db.Products let c=GetCategories() select new ProjectedProduct { SKU=p.ProductID.ToString(), Name=p.ProductName.ToString(), Categories=GetCategories() }; Assert.AreEqual(77, results.Count()); }
FAIL
8 changes: 8 additions & 0 deletions _posts/2009-04-03-many_to_many.markdown
@@ -0,0 +1,8 @@
---
layout: post
title: "Many to Many"
---

# Many to Many

Many to Many joins are joins between tables that are "non-structural" and instead, are logical. This means that the relationship is not necessarily enforced by your database engine and must be handled in code for the most part (this is only sort of true). For instance, if you have a Products table that can have one or more Categories assigned to it, and a Categories with one or more Products assigned to it, you have a Many to Many. To facilitate this structure in your database you need a "joining" or "mapping" table, which has a composite primary key made up of the primary key of the main tables - so in this example it would be ProductID and CategoryID together defining the primary key. You don't have to do it this way, but if you do SubSonic will love you for it because we can then spin some magic up for you.
12 changes: 12 additions & 0 deletions _posts/2009-04-03-paging.markdown
@@ -0,0 +1,12 @@
---
layout: post
title: "Paging"
---

# Paging

SubSonic supports server-side paging using Sql Server 2000, 2005, and MySQL. To use paging, simply make a call to the Paged method inline in the query:[Test] public void Exec_PagedSimple() { SubSonic.SqlQuery q = Select.AllColumnsFrom<Product>().Paged(1, 20) .Where("productid").IsLessThan(100); int records = q.GetRecordCount(); Assert.IsTrue(records

<h2> 20); } [Test] public void Exec_PagedJoined() { SubSonic.SqlQuery q = new Select("ProductId", "ProductName", "CategoryName") .From("Products").InnerJoin(Category.Schema).Paged(1, 20); int records = q.GetRecordCount(); Assert.IsTrue(records == 20); } [Test] public void Exec_PagedView() { SubSonic.SqlQuery q = new Select().From(Invoice.Schema).Paged(1, 20); int records = q.GetRecordCount(); Assert.IsTrue(records == 20); } [Test] public void Exec_PagedViewJoined() { SubSonic.SqlQuery q = new Select() .From(Invoice.Schema).Paged(1, 20).InnerJoin(Product.Schema); int records = q.GetRecordCount(); Assert.IsTrue(records </h2>

20); }
34 changes: 34 additions & 0 deletions _posts/2009-04-03-query_surface.markdown

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions _posts/2009-04-03-querying_views.markdown
@@ -0,0 +1,8 @@
---
layout: post
title: "Querying Views"
---

# Querying Views

Views are supported as read-only objects in SubSonic. You can't update or save information from a view, but these objects are super handy when you have complex data structures. Querying them is exactly the same as with tables, and you have full strongly-typed collection support as well. In general, Views can cause confusion in your application between developers on your team. Invariably business logic will tend to creep in, and those unfamiliar with SQL will be at a disadvantage in your group. We strongly suggest you let the query tool work to your advantage and don't use Views. You'll sleep better at night.
8 changes: 8 additions & 0 deletions _posts/2009-04-03-road_map.markdown
@@ -0,0 +1,8 @@
---
layout: post
title: "Road Map"
---

# Road Map

##[The Road Ahead]()
9 changes: 9 additions & 0 deletions _posts/2009-04-03-simple_aggregate_queries.markdown
@@ -0,0 +1,9 @@
---
layout: post
title: "Simple Aggregate Queries"
---

# Simple Aggregate Queries

Running aggregates with SubSonic is pretty straightforward, but is a bit limited if you're trying to run analytical analysis or some deeper queries. SubSonic is built with the "80%" situation in mind - perhaps the quick query where you need a Count, MAX, MIN, or Average. These methods are here for you to work with, but if you need some additional "love" aggregate-style, I might suggest you use the
;

0 comments on commit 6204492

Please sign in to comment.