Example #1
0
        public void TestLinqBasics()
        {
            Startup.BooksApp.LogTestStart();

            var        app = Startup.BooksApp;
            IDbCommand lastCmd;

            //Init
            var session = app.OpenSession();
            var books   = session.EntitySet <IBook>();
            var authors = session.EntitySet <IAuthor>();
            var users   = session.EntitySet <IUser>();
            var pubs    = session.EntitySet <IPublisher>();

            var csTitle = "c# Programming";
            var vbTitle = "VB Programming";

            // new + new
            var idTitles = books.Select(b => new { Id1 = b.Id, Title1 = b.Title })
                           .Select(b => new { Id2 = b.Id1, Title2 = b.Title1 }).ToList();

            Assert.IsTrue(idTitles.Count > 0, "Expected Id-Title pairs");

            // book by title
            var qBooksByTitle = from b in books
                                where b.Title == csTitle
                                select b;
            var lstBooksByTitle = qBooksByTitle.ToList();

            Assert.IsTrue(lstBooksByTitle.Count > 0, "Books by title failed.");

            // Books by publisher's name; skip, take test
            var msbooks = from b in books
                          where b.Publisher.Name == "MS Books"
                          orderby b.Title.ToUpper() //ToUpper for Oracle, case-sensitive
                          select b;

            var msBookList = msbooks.ToList();

            Assert.AreEqual(3, msBookList.Count, "Invalid number of MS books.");
            var msbook0 = msBookList[0]; //c# book should be the first book when sorted by title

            Assert.AreEqual("c# Programming", msbook0.Title, "Invalid title of c# book.");
            //Same with skip, take
            var qSkipTake   = msbooks.Skip(1).Take(1);
            var lstSkipTake = qSkipTake.ToList();

            Assert.AreEqual(1, lstSkipTake.Count, "Invalid # of books in skip/take.");
            // Just some sanity check, ran into strange behavior here with session.LastCommand
            lastCmd = session.GetLastCommand();
            Assert.IsTrue(lastCmd.CommandText.Contains("'MS Books'"), "Investigate: LastCommand contains wrong command: " + lastCmd.CommandText);

            // Test bitwise op in SQL. Finding books by editions - we use bit-wise operation on book.Editions property - which is a flagset enum
            session = app.OpenSession();
            books   = session.EntitySet <IBook>();
            var eBooks = from b in books
                         where (b.Editions & BookEdition.EBook) != 0
                         select b;
            var eBooksList = eBooks.ToList();

            Assert.IsTrue(eBooksList.Count == 1, "Invalid number of e-books");

            // Using == for entity objects in queries
            var progCat  = BookCategory.Programming;
            var msPub    = session.EntitySet <IPublisher>().Single(p => p.Name == "MS Books");
            var msbooks2 = from b in books
                           where b.Publisher == msPub && b.Category == progCat
                           orderby b.Title
                           select b;

            msBookList = msbooks2.ToList();
            Assert.IsTrue(msBookList.Count > 0, "Query with entity object == comparison failed.");

            //BookAuthors link table
            var bookAuthors = session.EntitySet <IBookAuthor>();
            var aJack       = session.EntitySet <IAuthor>().Where(a => a.FirstName == "Jack").First();
            var qBA         = from ba in bookAuthors
                              where ba.Author == aJack && ba.Book.Title == "c# Programming"
                              select ba;
            var lstBAs = qBA.ToList();

            Assert.IsTrue(lstBAs.Count > 0, "Failed to find book-author record by author and book title.");

            // LINQ with FirstOrDefault() - these are executed slightly differently from queries that return result sets
            session = app.OpenSession();
            var msp = (from p in session.EntitySet <IPublisher>()
                       where p.Name == "MS Books"
                       select p).FirstOrDefault();

            Assert.IsTrue(msp != null, "Query with FirstOrDefault failed.");
            Assert.AreEqual("MS Books", msp.Name, "Query with FirstOrDefault failed, invalid name.");
            //Check that entity is attached to session
            var mspRec = EntityHelper.GetRecord(msp);

            Assert.IsTrue(mspRec.Session != null, "FirstOrDefault query failed: the result record is not attached to session.");
            Assert.IsTrue(msp.Books.Count > 0, "Failed to read publisher's books: entity is not attached to session.");

            // Query that returns a derived entity, different from the original 'EntitySet' entity
            session = app.OpenSession();
            //Return publishers of books in Kids category - we have one kids book, so expect one pub record
            var kidPubs = from b in session.EntitySet <IBook>()
                          where b.Category == BookCategory.Kids
                          select b.Publisher;
            var listPubs = kidPubs.ToList();

            Assert.AreEqual(1, listPubs.Count, "Unexpected pub count in special LINQ query.");
            // The same but with FirstOrDefault
            var firstKidPub = (from b in session.EntitySet <IBook>()
                               where b.Category == BookCategory.Kids
                               select b.Publisher).FirstOrDefault();

            Assert.IsNotNull(firstKidPub, "First kid Publisher is null in special LINQ query.");

            // Test FirstOrDefault with null result - special case for EntityCache.CloneEntity method
            session = app.OpenSession();
            var none = session.EntitySet <IBook>().Where(b => b.Title == "123").FirstOrDefault();

            Assert.IsNull(none, "FirstOrDefault with null result failed.");

            // Query returning anonymous type
            // Return pairs book-title, price
            session = app.OpenSession();
            var someId       = Guid.Empty;
            var qryBooksAnon = from b in session.EntitySet <IBook>()
                               where b.Category == BookCategory.Programming
                               select new { Id = b.Id.ToString(), Title = b.Title, Price = b.Price }; //testing how ToString() works with Guids - only in select output!
            var listBooksAnon = qryBooksAnon.ToList();

            Assert.IsTrue(listBooksAnon.Count > 0, "Failed to retrieve anon type.");
            Assert.IsTrue(!string.IsNullOrEmpty(listBooksAnon[0].Id), "ToString query translation failed");

            //Same but with parameter in output
            var someKey       = "someKey"; //some value to include into results - testing how such field initialized from parameter is handled
            var qryBooksAnon2 = from b in session.EntitySet <IBook>()
                                where b.Category == BookCategory.Programming
                                select new { b.Title, b.Price, Key = someKey };
            var listBooksAnon2 = qryBooksAnon2.ToList();

            Assert.IsTrue(listBooksAnon2.Count > 0, "Failed to retrieve anon type.");

            // Return pairs of (book, publisher)
            session = app.OpenSession();
            var bpPairs = from b in session.EntitySet <IBook>()
                          where b.Category == BookCategory.Programming
                          select new { Book = b, Publisher = b.Publisher };
            var bpPairsList = bpPairs.ToList();

            Assert.IsTrue(bpPairsList.Count > 0, "Failed to retrieve anon type.");

            // Return anon type with pair of entities, one of them is nullable
            session = app.OpenSession();
            var qAuthorUser = from a in authors
                              select new { Author = a, User = a.User };
            var listAuthorUser = qAuthorUser.ToList();

            Assert.IsTrue(listAuthorUser.Count > 0, "Author-User query failed.");
            // Author Jim Hacker is not a user, so its User prop should be null
            var jimInfo = listAuthorUser.First(au => au.Author.LastName == "Hacker");

            Assert.IsTrue(jimInfo.User == null, "User prop is not null for Author Jim Hacker");

            // Some odd query returning list of constants
            books = session.EntitySet <IBook>();
            var numberQuery = from b in books
                              where b.Publisher.Name == "MS Books"
                              select 1;
            var numbersFromQuery = numberQuery.ToList();

            Assert.IsTrue(numbersFromQuery.Count > 0, "Number query did not return rows");

            // Join thru nullable reference - it should work even with cache!
            var qAuthorsJohn = from a in authors
                               where a.User.UserName == "John"
                               select a;
            var lstAuthorsJohn = qAuthorsJohn.ToList();

            Assert.AreEqual(1, lstAuthorsJohn.Count, "Failed to find author by user name");


            // Aggregate methods
            session = app.OpenSession();
            books   = session.EntitySet <IBook>();
            var maxPrice = books.Max(b => b.Price);

            Assert.IsTrue(maxPrice > 0, "Max price is invalid.");
            // Queryable.Average method is special in some way - it is not a generic on result type, but has a number of overloads
            // for specific numeric types. This test checks how fwk handles this
            var avgPrice = books.Average(b => b.Price);

            Assert.IsTrue(avgPrice > 0, "Average price is invalid.");

            // Test 'locally evaluatable' pieces in queries
            session = app.OpenSession();
            pubs    = session.EntitySet <IPublisher>();
            var msBooksName = "local var value";

            _someClassField = "field value";
            // NOTE: a bug in PostGres npgsql (version v2.1.3/Sept 2014); in the following query, if we put literal "Literal'string" before
            //       any expr involving parameter, then provider/postgres fails with error 42703 'Column P0 does not exist'
            //       But if value with quote is after all parameters, everything works fine! To see it, just uncomment the clause below
            var pq = from p in pubs
                     where
                     p.Name == msBooksName      // param in query
                                                //|| p.Name != "Postgres'fails"
                     || p.Name == _someClassField || //param
                     p.Name == SomeClassProp || //param
                     p.Name == PublisherNameConst || // const in query, not parameters
                     p.Name == "Literal'string" || //const (literal)
                     p.Name != "blah"              //const
                     select p;
            var pqList = pq.ToList();

            Assert.IsTrue(pqList.Count > 0, "Query with local variables failed.");

            //Using extra container object
            var qparams = new QueryParamsContainer()
            {
                Field = csTitle, Prop = vbTitle
            };
            var qBooksWithParamObj = from b in books
                                     where b.Title == qparams.Field || b.Title == qparams.Prop
                                     select b;
            var lstBooksWithParamObj = qBooksWithParamObj.ToList();

            Assert.AreEqual(2, lstBooksWithParamObj.Count, "Query with param object failed");

            // Test using predicates comparing with null. It is special case - must be translated to 'IS NULL' in SQL
            var bq = from b in books
                     where b.Abstract == null
                     select b;
            var booksWithoutAbstract = bq.ToList();

            Assert.IsTrue(booksWithoutAbstract.Count > 0, "Query with predicate checking for null failed.");
            // testing entity reference null check (foreign key != null)
            var qAuthUsers = from a in authors
                             where a.User != null
                             select a;
            var lstAuthUsers = qAuthUsers.ToList();

            Assert.IsTrue(lstAuthUsers.Count > 0, "Query with check for non null failed.");

            // Test using calculations over local values directly into the query. Did not work initially, now fixed.
            // The date value should be calculated before running the query and supplied as parameter. Same with price
            var priceCutOff = 5;
            Func <decimal, decimal> getDiscountedPrice = (decimal p) => p * 0.8m;
            var queryWithCalc = session.EntitySet <IBook>().Where(b => b.PublishedOn > DateTime.Now.AddYears(-3) && b.Price > getDiscountedPrice(priceCutOff));
            var lstFromCalc   = queryWithCalc.ToList();

            lastCmd = session.GetLastCommand(); //to check SQL in debugger
            Assert.IsTrue(lstFromCalc.Count > 0, "Query with local calc values failed.");

            // Test for MySql handling of Guid IDs
            // Must use an entity that is not in full entity cache: like IBookOrder, not IBook.
            session = app.OpenSession();
            var someOrder     = session.GetEntities <IBookOrder>(take: 10).First();
            var someOrderId   = someOrder.Id;
            var qGetOrderById = from bo in session.EntitySet <IBookOrder>()
                                where bo.Id == someOrderId
                                select bo;
            var listOrders = qGetOrderById.ToList();

            Assert.AreEqual(1, listOrders.Count, "Failed to get order by Id.");
            Assert.AreEqual(someOrderId, listOrders[0].Id, "Failed to get order by Id.");

            // Linq query against entity with computed column
            // Testing loading entity with computed column; I've encountered trouble with computed columns in new linq engine, so verifying the fix here.
            // Important - we should use entity that is NOT in full cache, like IBookOrder (it has computed field Summary).
            var orders  = session.EntitySet <IBookOrder>();
            var qOrders = from ord in orders
                          where ord.Status == OrderStatus.Completed
                          select ord;
            var lstOrders = qOrders.ToList();

            Assert.IsTrue(lstOrders.Count > 0, "Failed to retrieve orders.");
            var summ0 = lstOrders[0].Summary;

            Assert.IsFalse(string.IsNullOrWhiteSpace(summ0), "Failed to read order summary");

            //Test string concatenation
            var authFullNames = session.EntitySet <IAuthor>().Select(a => a.LastName + ", " + a.FirstName).ToList();

            Assert.IsTrue(authFullNames.Count > 0, "Expected non-empty list.");
            Assert.IsTrue(authFullNames.Contains("Sharp, John"), "Expected john sharp in the list.");
            //Test string Length methods
            var authNameLens = session.EntitySet <IAuthor>().Select(a => a.LastName.Length + a.FirstName.Length).ToList();

            Assert.IsTrue(authNameLens.Count > 0, "Expected non-empty list of name lengths.");
            lastCmd = session.GetLastCommand();

            // decimal linq params
            decimal pr             = 5.0m;
            var     expensiveBooks = session.EntitySet <IBook>().Where(b => b.Price > pr).ToList();

            lastCmd = session.GetLastCommand();
            Assert.IsTrue(expensiveBooks.Count > 0, "Query with decimal param failed.");
        }
Example #2
0
        public void TestLinqBasics()
        {
            var app = SetupHelper.BooksApp;
              SetupHelper.InvalidateCache();
              //Init
              var session = app.OpenSession();
              var books = session.EntitySet<IBook>();
              var authors = session.EntitySet<IAuthor>();
              var users = session.EntitySet<IUser>();
              var pubs = session.EntitySet<IPublisher>();

              var csTitle = "c# Programming";
              var vbTitle = "VB Programming";

              // book by title
              var qBooksByTitle = from b in books
                          where b.Title == csTitle
                          select b;
              var lstBooksByTitle = qBooksByTitle.ToList();
              Assert.IsTrue(lstBooksByTitle.Count > 0, "Books by title failed.");

              // Books by publisher's name; skip, take test
              var msbooks = from b in books
                    where b.Publisher.Name == "MS Books"
                    orderby b.Title
                    select b;
              var msBookList = msbooks.ToList();
              Assert.AreEqual(3, msBookList.Count, "Invalid number of MS books.");
              var msbook0 = msBookList[0]; //c# book should be the first book when sorted by title
              Assert.IsTrue(msbook0.Title == "c# Programming", "Invalid title of c# book.");
              //Same with skip, take
              var qSkipTake = msbooks.Skip(1).Take(1);
              var lstSkipTake = qSkipTake.ToList();
              Assert.IsTrue(lstSkipTake.Count == 1, "Invalid # of books in skip/take.");

              // Test bitwise op in SQL. Finding books by editions - we use bit-wise operation on book.Editions property - which is a flagset enum
              session = app.OpenSession();
              books = session.EntitySet<IBook>();
              var eBooks = from b in books
                   where (b.Editions & BookEdition.EBook) != 0
                   select b;
              var eBooksList = eBooks.ToList();
              Assert.IsTrue(eBooksList.Count == 1, "Invalid number of e-books");

              // Using == for entity objects in queries
              var progCat = BookCategory.Programming;
              var msPub = session.EntitySet<IPublisher>().Single(p => p.Name == "MS Books");
              var msbooks2 = from b in books
                     where b.Publisher == msPub && b.Category == progCat
                     orderby b.Title
                     select b;
              msBookList = msbooks2.ToList();
              Assert.IsTrue(msBookList.Count > 0, "Query with entity object == comparison failed.");

              //BookAuthors link table
              var bookAuthors = session.EntitySet<IBookAuthor>();
              var aJack = session.EntitySet<IAuthor>().Where(a => a.FirstName == "Jack").First();
              var qBA = from ba in bookAuthors
                where ba.Author == aJack && ba.Book.Title == "c# Programming"
                select ba;
              var lstBAs = qBA.ToList();
              Assert.IsTrue(lstBAs.Count > 0, "Failed to find book-author record by author and book title.");

              // LINQ with FirstOrDefault() - these are executed slightly differently from queries that return result sets
              session = app.OpenSession();
              var msp = (from p in session.EntitySet<IPublisher>()
                 where p.Name == "MS Books"
                 select p).FirstOrDefault();
              Assert.IsTrue(msp != null, "Query with FirstOrDefault failed.");
              Assert.AreEqual("MS Books", msp.Name, "Query with FirstOrDefault failed, invalid name.");
              //Check that entity is attached to session
              var mspRec = EntityHelper.GetRecord(msp);
              Assert.IsTrue(mspRec.Session != null, "FirstOrDefault query failed: the result record is not attached to session.");
              Assert.IsTrue(msp.Books.Count > 0, "Failed to read publisher's books: entity is not attached to session.");

              // Query that returns a derived entity, different from the original 'EntitySet' entity
              session = app.OpenSession();
              //Return publishers of books in Kids category - we have one kids book, so expect one pub record
              var kidPubs = from b in session.EntitySet<IBook>()
                    where b.Category == BookCategory.Kids
                    select b.Publisher;
              var listPubs = kidPubs.ToList();
              Assert.AreEqual(1, listPubs.Count, "Unexpected pub count in special LINQ query.");
              // The same but with FirstOrDefault
              var firstKidPub = (from b in session.EntitySet<IBook>()
                         where b.Category == BookCategory.Kids
                         select b.Publisher).FirstOrDefault();
              Assert.IsNotNull(firstKidPub, "First kid Publisher is null in special LINQ query.");

              // Test FirstOrDefault with null result - special case for EntityCache.CloneEntity method
              session = app.OpenSession();
              var none = session.EntitySet<IBook>().Where(b => b.Title == "123").FirstOrDefault();
              Assert.IsNull(none, "FirstOrDefault with null result failed.");

              // Query returning anonymous type
              // Return pairs book-title, price
              session = app.OpenSession();
              var someId = Guid.Empty;
              var qryBooksAnon = from b in session.EntitySet<IBook>()
                         where b.Category == BookCategory.Programming
                         select new { Id = b.Id.ToString(), Title = b.Title, Price = b.Price }; //testing how ToString() works with Guids - only in select output!
              var listBooksAnon = qryBooksAnon.ToList();
              Assert.IsTrue(listBooksAnon.Count > 0, "Failed to retrieve anon type.");
              Assert.IsTrue(!string.IsNullOrEmpty(listBooksAnon[0].Id), "ToString query translation failed");

              //Same but with parameter in output
              //SQL CE does not allow this (query like: SELECT Title, Price, @P3)
              if (SetupHelper.ServerType != DbServerType.SqlCe) {
            var someKey = "someKey"; //some value to include into results - testing how such field initialized from parameter is handled
            var qryBooksAnon2 = from b in session.EntitySet<IBook>()
                            where b.Category == BookCategory.Programming
                            select new { b.Title, b.Price, Key = someKey };
            var listBooksAnon2 = qryBooksAnon2.ToList();
            Assert.IsTrue(listBooksAnon2.Count > 0, "Failed to retrieve anon type.");
              }

              // Return pairs of (book, publisher)
              session = app.OpenSession();
              var bpPairs = from b in session.EntitySet<IBook>()
                        where b.Category == BookCategory.Programming
                        select new { Book = b, Publisher = b.Publisher };
              var bpPairsList = bpPairs.ToList();
              Assert.IsTrue(bpPairsList.Count > 0, "Failed to retrieve anon type.");

              // Return anon type with pair of entities, one of them is nullable
              session = app.OpenSession();
              var qAuthorUser = from a in authors
               select new { Author = a, User = a.User };
              var listAuthorUser = qAuthorUser.ToList();
              Assert.IsTrue(listAuthorUser.Count > 0, "Author-User query failed.");
              // Author Jim Hacker is not a user, so its User prop should be null
              var jimInfo = listAuthorUser.First(au => au.Author.LastName == "Hacker");
              Assert.IsTrue(jimInfo.User == null, "User prop is not null for Author Jim Hacker");

              // Some odd query returning list of constants
              books = session.EntitySet<IBook>();
              var numberQuery = from b in books
                        where b.Publisher.Name == "MS Books"
                        select 1;
              var numbersFromQuery = numberQuery.ToList();
              Assert.IsTrue(numbersFromQuery.Count > 0, "Number query did not return rows");

              // Join thru nullable reference - it should work even with cache!
              var qAuthorsJohn = from a in authors
                         where a.User.UserName == "John"
                         select a;
              var lstAuthorsJohn = qAuthorsJohn.ToList();
              Assert.AreEqual(1, lstAuthorsJohn.Count, "Failed to find author by user name");

              // Aggregate methods
              session = app.OpenSession();
              books = session.EntitySet<IBook>();
              var maxPrice = books.Max(b => b.Price);
              Assert.IsTrue(maxPrice > 0, "Max price is invalid.");
              // Queryable.Average method is special in some way - it is not a generic on result type, but has a number of overloads
              // for specific numeric types. This test checks how fwk handles this
              var avgPrice = books.Average(b => b.Price);
              Assert.IsTrue(avgPrice > 0, "Average price is invalid.");

              // Test 'locally evaluatable' pieces in queries
              session = app.OpenSession();
              pubs = session.EntitySet<IPublisher>();
              var msBooksName = "local var value";
              _someClassField = "field value";
              // NOTE: a bug in PostGres npgsql (version v2.1.3/Sept 2014); in the following query, if we put literal "Literal'string" before
              //       any expr involving parameter, then provider/postgres fails with error 42703 'Column P0 does not exist'
              //       But if value with quote is after all parameters, everything works fine! To see it, just uncomment the clause below
              var pq = from p in pubs
               where
                        p.Name == msBooksName  // param in query
                     //|| p.Name != "Postgres'fails"
                     || p.Name == _someClassField //param
                     || p.Name == SomeClassProp   //param
                     || p.Name == PublisherNameConst // const in query, not parameters
                     || p.Name == "Literal'string" //const (literal)
                     || p.Name != "blah"           //const
               select p;
              var pqList = pq.ToList();
              Assert.IsTrue(pqList.Count > 0, "Query with local variables failed.");

              //Using extra container object
              var qparams = new QueryParamsContainer() { Field = csTitle, Prop = vbTitle };
              var qBooksWithParamObj = from b in books
                               where b.Title == qparams.Field || b.Title == qparams.Prop
                               select b;
              var lstBooksWithParamObj = qBooksWithParamObj.ToList();
              Assert.AreEqual(2, lstBooksWithParamObj.Count, "Query with param object failed");

              // Test using predicates comparing with null. It is special case - must be translated to 'IS NULL' in SQL
              var bq = from b in books
               where b.Abstract == null
               select b;
              var booksWithoutAbstract = bq.ToList();
              Assert.IsTrue(booksWithoutAbstract.Count > 0, "Query with predicate checking for null failed.");
              // testing entity reference null check (foreign key != null)
              var qAuthUsers = from a in authors
                        where a.User != null
                        select a;
              var lstAuthUsers = qAuthUsers.ToList();
              Assert.IsTrue(lstAuthUsers.Count > 0, "Query with check for non null failed.");

              // Test using calculations over local values directly into the query. Did not work initially, now fixed.
              // The date value should be calculated before running the query and supplied as parameter. Same with price
              var priceCutOff = 5;
              Func<decimal, decimal> getDiscountedPrice = (decimal p) => p * 0.8m;
              var queryWithCalc = session.EntitySet<IBook>().Where(b => b.PublishedOn > DateTime.Now.AddYears(-3) && b.Price > getDiscountedPrice(priceCutOff));
              var lstFromCalc = queryWithCalc.ToList();
              var cmd = session.GetLastCommand(); //to check SQL in debugger
              Assert.IsTrue(lstFromCalc.Count > 0, "Query with local calc values failed.");

              // Test for MySql handling of Guid IDs
              // Must use an entity that is not in full entity cache: like IBookOrder, not IBook.
              session = app.OpenSession();
              var someOrder = session.GetEntities<IBookOrder>(take: 10).First();
              var someOrderId = someOrder.Id;
              var qGetOrderById = from bo in session.EntitySet<IBookOrder>()
                     where bo.Id == someOrderId
                     select bo;
              var listOrders = qGetOrderById.ToList();
              Assert.AreEqual(1, listOrders.Count, "Failed to get order by Id.");
              Assert.AreEqual(someOrderId, listOrders[0].Id, "Failed to get order by Id.");

              // Linq query against entity with computed column
              // Testing loading entity with computed column; I've encountered trouble with computed columns in new linq engine, so verifying the fix here.
              // Important - we should use entity that is NOT in full cache, like IBookOrder (it has computed field Summary).
              var orders = session.EntitySet<IBookOrder>();
              var qOrders = from ord in orders
                    where ord.Status == OrderStatus.Completed
                    select ord;
              var lstOrders = qOrders.ToList();
              Assert.IsTrue(lstOrders.Count > 0, "Failed to retrieve orders.");
              var summ0 = lstOrders[0].Summary;
              Assert.IsFalse(string.IsNullOrWhiteSpace(summ0), "Failed to read order summary");

              //Test string concatenation
              var authFullNames = session.EntitySet<IAuthor>().Select(a => a.LastName + ", " + a.FirstName).ToList();
              Assert.IsTrue(authFullNames.Count > 0, "Expected non-empty list.");
              Assert.IsTrue(authFullNames.Contains("Sharp, John"), "Expected john sharp in the list.");
              //Test string Length methods
              var authNameLens = session.EntitySet<IAuthor>().Select(a => a.LastName.Length + a.FirstName.Length).ToList();
              Assert.IsTrue(authNameLens.Count > 0, "Expected non-empty list of name lengths.");
              cmd = session.GetLastCommand();
        }