-
Notifications
You must be signed in to change notification settings - Fork 21
Deflated References
Deflated References are a powerful and unique feature of Shaolinq. They allow you to:
- Update objects in a single trip to the database (no read-first required).
- Access primary keys of related objects in an object-oriented fashion without requiring an extra query or a join
- Set relationships without requiring any extra queries.
- Query for objects with complex primary keys (primary keys where the primary key is made up of other Data Access Objects) without having to first query the objects that make up the complex primary key.
- Use properties of an object you only know the primary key (deflated reference) within a query without first having to load the entire object. The property value will be resolved in SQL on the server side.
You can create a deflated reference by using the GetReference method available on DataAccessObjects and RelatedDataAccessObjects objects.
var book = model.Books.GetReference(bookId);If you're using a composite primary key you can pass in an anonymous type
var book = model.AdvancedBooks.GetReference(new { BookId = bookId, LocationId = location Id });If you have DAOs with primary keys that are themselves DAOs then you can recursively use GetReference:
var book = model.SuperAdvancedBooks.GetReference(new { Title = title, Author = model.Authors.GetReference(new { Id = authorId, Name = authorName }));All properties except primary keys on deflated references a write-only until they've been written to once. If you try to read a non-primary key property the entire object will be implicitly Inflated.
var book = model.Books.GetReference(bookId);
var s = book.Title; // Implicit inflation on access to non-PrimaryKeySELECT T1.Id, T1.Title FROM Book as T1;You can also explicitly inflate an object by calling the Inflate extension method on DataAccessObject.
var book = model.Books.GetReference(bookId);
var s = book.Inflate(); // SQLSELECT T1.Id, T1.Title FROM Book as T1;Because Shaolinq maintains object identity within a single transaction, querying for the same object will cause the original reference to be inflated.
var book = model.Books.GetReference(bookId);
var sameBook = model.Books.Single(c => c.Id == bookId);
Assert.IsTrue(object.ReferenceEquals(book, sameBook)); SELECT T1.Id, T1.Title FROM Book as T1;If you were to inflate an object that uses a complex primary key (primary keys made of one or more DAOs), you can see the SQL generated is well formed:
var book = model.SuperAdvancedBooks.GetReference(new { Title = title, Author = model.Authors.GetReference(new { Id = authorId, Name = authorName }));
book.Inflate();SELECT Id, Title, AuthorId, AuthorName FROM SuperAdvancedBooks WHERE Title = title AND AuthorId = authorId AND AuthorName = authorName;Because deflated references look exactly like normal objects and can be written to, it's easy to do a single-trip update to an object if you know its primary key.
using (var scope = new DataAccessScope)
{
var book = model.Books.GetReference(bookId);
book.Title = "Hello";
scope.Complete();
}UPDATE Book SET T1.Title="Hello" WHERE Book.Id = bookId;Shaolinq will defer deflated reference inflation as long as possible. This makes it possible to perform advanced queries that would not usually be available with other ORMs by using natural object/LINQ syntax.
For example, it is possible to reference properties of a deflated reference without first deflating it. You can do this by dereferencing the property on a deflated reference from within a LINQ query.
// Does not result in a DB query
var book = model.Books.GetReference(bookId);
// The property access 'book.AuthorName' is evaluated on the server-side rather than client-side
var index = model.Authors.FirstOrDefault(c => c.Name == book.AuthorName);SELECT T1.Id, T1.Name FROM Author AS T1 WHERE T1.Name =
(SELECT T2.AuthorName FROM Book AS T2 WHERE T2.Id = bookId LIMIT 2)This also works if the deflated reference is a deflated predicated reference. These types of deflated references don't even know their primary key but define a predicate/query for resolving the correct object.
// Does not result in a DB query
var book = model.Books.GetReference(c => c.Title = "Peter Rabbit");
// The property access 'book.AuthorName' is evaluated on the server-side rather than client-side
var index = model.Authors.FirstOrDefault(c => c.Name == book.AuthorName);SELECT T1.Id, T1.Name FROM Author AS T1 WHERE T1.Name =
(SELECT T2.AuthorName FROM Book AS T2 WHERE T2.Title = "Peter Rabbit" LIMIT 2)Copyright (c) 2018 Thong Nguyen (tumtumtum@gmail.com)