It’s a technology-oriented console application showing a set of improvements introduced in DataObjects.Net 2.2:

  • It shows new features of Query;
  • It utilizes ValueTypes and ValueTypeCollections.

Sample output

DataObjects.Net: Articles demo

Select database server to use:
1) Microsoft SQL Server
2) Oracle
3) Native Oracle
4) SAP DB
> 1
Selected: Microsoft SQL Server.
Reading product key...

Building domain...
Connection URL: mssql://127.0.0.1/DataObjectsDotNetDemos
Driver:         Microsoft SQL Server\MSDE database driver for DataObjects.Net
  OK.
Creating data...
  OK.
Querying data...

> All articles which author's name starts with 'Tyler':
  Query: "Select Article instances where {Author.Name} like 'Tyler%'"
> Or the same, but by another way:
  Query: "Select Article instances require $root.Author[{Name} like 'Tyler%']"
> Last query uses 'inner join', so it should work faster.
  Result: 2 objects.
    Survival Instinct
    Anarchy
Press enter to continue...

> Authors ordered by the publishing date. Unpublished authors go first ('let' re
sults in 'left join' here):
  Query: "Select Author instances let $root.Articles $A order by {$A.Date}"
  Result: 5 objects.
    Marla Singer
    Anonymous
    Tyler Durden
    Anonymous
    Tyler Durden
Press enter to continue...

> Articles published after the specified date, but containing articles that were
 published before that date in SeeAlso:
  Query: "Select Article instances where {Date}>@Date and {(Article)SeeAlso[{Dat
e}<@Date].count}>0"
  Result: 1 objects.
    Anarchy
Press enter to continue...

> Querying the whole collection: checks Article.SeeAlso for object of type Artic
le:
  Query: "Select (Article)Article.SeeAlso instances"
  Result: 4 objects.
    Car accidents
    Corporations
    Corporations
    Survival Instinct
Press enter to continue...

> Articles having references to FTP sites:
  Query: "Select Article instances where {References[{URL} like 'ftp://%'].count
} > 0"
  Result: 1 objects.
    Car accidents
Press enter to continue...

> Comments by Tyler Durden ordered by Article date:
  Query: "Select Article.Comments values where 'Tyler Durden' = any{Author.Name}
 order by {parent.Date}"
  Result: 2 values.
    You'd look deeper.
    No comments...
Press enter to continue...

> Quotes with length > 50:
  Query: "Select Author.Quotes values where len({Body}) > 50"
  Result: 3 values.
    It's only after you've lost everything that you're free to do anything.
    When you have insomnia, you're never really asleep... and you're never reall
y awake.
    On a long enough timeline, the survival rate for everyone drops to zero.

Press Enter to close...

Model.cs

using System;
using System.Data;
using DataObjects.NET;
using DataObjects.NET.Attributes;
using DataObjects.NET.FullText;

namespace Demo_Articles.Model
{
  public abstract class Article: DataObject
  {
    [Translatable]
    public abstract string Title {get; set;}

    [Translatable]
    public abstract string Annotation {get; set;}

    [Translatable]
    [SqlType(SqlType.Text)]
    [LoadOnDemand]
    public abstract string Body {get; set;}

    public abstract DateTime Date {get; set;}

    public abstract Author Author { get; set; }

    [ItemType(typeof(DataObject))]
    public abstract DataObjectCollection SeeAlso { get; }

    [Alias("Refs")]
    [DbName("Refs")]
    [ItemType(typeof(Reference))]
    public abstract ValueTypeCollection References { get; }

    [ItemType(typeof(Comment))]
    public abstract ValueTypeCollection Comments { get; }
  }

  public abstract class Author: DataObject
  {
    public abstract string Name {get; set;}

    public abstract Reference Homepage {get; set;}

    [ItemType(typeof(Article))]
    [PairTo(typeof(Article), "Author")]
    public abstract DataObjectCollection Articles { get; }

    [Translatable]
    [ItemType(typeof(Quote))]
    public abstract ValueTypeCollection Quotes { get; }
  }

  [Serializable]
  public struct Reference
  {
    [Alias("URL")]
    [DbName("URL")]
    public string Url;

    [Nullable]
    public string Description;

    public Reference(string url, string description)
    {
      Url = url;
      Description = description;
    }

    public Reference(string url)
    {
      Url = url;
      Description = null;
    }
  }

  [Serializable]
  public struct Comment
  {
    public Author Author;

    [SqlType(SqlType.Text)]
    public string Body;
    
    public Comment(Author author, string body)
    {
      Author = author;
      Body = body;
    }
  }

  [Serializable]
  public struct Quote
  {
    [Length(250)]
    public string Body;
    
    public Quote(string body)
    {
      Body = body;
    }
  }
}

Articles.cs

using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Globalization;

using DataObjects.NET;
using DataObjects.NET.Attributes;
using DataObjects.NET.FullText;
using DataObjects.NET.RuntimeServices;
using DataObjects.NET.ObjectModel;
using Demo_Articles.Model;

namespace Demo_Articles
{
  class Articles
  {
    static Domain   domain;
    static string   connectionUrl = "";

    [STAThread]
    static void Main(string[] args)
    {
      Console.WriteLine("DataObjects.Net: Articles demo\n");
      SelectDatabase();
      CreateDomain();

      CreateData();
      QueryData();

      Console.Write("\nPress Enter to close... ");
      Console.ReadLine();
    }

    static void SelectDatabase()
    {
      while (connectionUrl=="") 
      {
        Console.Write("Select database server to use:\n" +
          "1) Microsoft SQL Server\n" +
          "2) Oracle\n" +
          "3) Native Oracle\n" +
          "4) SAP DB\n" +
          "> ");
        string dbType = Console.ReadLine();
        switch (dbType) 
        {
          case "1":
            Console.WriteLine("Selected: Microsoft SQL Server.");
            connectionUrl = "mssql://127.0.0.1/DataObjectsDotNetDemos";
            break;
          case "2":
            Console.WriteLine("Selected: Oracle.");
            connectionUrl = "oracle://admin:admin@localhost/Demos";
            break;
          case "3":
            Console.WriteLine("Selected: Native Oracle.");
            connectionUrl = "nativeoracle://admin:admin@localhost/Demos";
            break;
          case "4":
            Console.WriteLine("Selected: SAP DB.");
            connectionUrl = "sapdb://ADMIN:ADMIN@localhost/DEMOS";
            break;
          default:
            Console.WriteLine("Illegal selection.");
            break;
        }
      }
    }
    
    static void CreateDomain()
    {
      Console.WriteLine("Reading product key...");
      string productKeyFile = @"..\..\..\..\ProductKey.txt"; 
      string productKey = "";
      if (File.Exists(productKeyFile))
        using (StreamReader sr = new StreamReader(productKeyFile)) 
        {
          productKey = sr.ReadToEnd().Trim();
        }

      Console.WriteLine("");
      Console.WriteLine("Building domain...");
      domain = new Domain(connectionUrl, productKey);
      Console.WriteLine("Connection URL: {0}",domain.ConnectionURL);
      Console.WriteLine("Driver:         {0}",domain.Driver.Info.Description);

      domain.RegisterCulture(new Culture("En","U.S. English", new CultureInfo("en-us",false)));
      domain.RegisterCulture(new Culture("Ru","Russian", new CultureInfo("ru-ru",false)));
      domain.Cultures["En"].Default = true;
      domain.RegisterTypes("Demo_Articles.Model");
      #if DEBUG
        domain.DebugInfoOutputFolder = @"C:\Debug";
      #endif
      domain.Build(DomainUpdateMode.Recreate);
      Console.WriteLine("  OK.");
    }
    
    static void CreateData()
    {
      Console.WriteLine("Creating data...");

      using (Session s = domain.CreateSession()) 
      {
        s.BeginTransaction();

        // Authors
      
        Author Tyler = (Author)s.CreateObject(typeof(Author));
        Tyler.Name   = "Tyler Durden";
        Tyler.Homepage = new Reference(
          "http://www.fightclub.com/",
          "Fight Club");

        Tyler.Quotes.Add(new Quote("You're not your job."));
        Tyler.Quotes.Add(new Quote("You're not how much money you have in the bank."));
        Tyler.Quotes.Add(new Quote("You're not the car you drive."));
        Tyler.Quotes.Add(new Quote("You're not the contents of your wallet."));
        Tyler.Quotes.Add(new Quote("You are not a beautiful or unique snowflake."));
        Tyler.Quotes.Add(new Quote("It's only after you've lost everything that you're free "+
                                   "to do anything."));
        
        Author Anonymous = (Author)s.CreateObject(typeof(Author));
        Anonymous.Name = "Anonymous";

        Anonymous.Quotes.Add(new Quote("When you have insomnia, you're never really asleep... " +
                                       "and you're never really awake."));
        Anonymous.Quotes.Add(new Quote("On a long enough timeline, the survival rate for "+
                                       "everyone drops to zero."));
        
        Author Marla = (Author)s.CreateObject(typeof(Author));
        Marla.Name   = "Marla Singer";

        // Articles
        
        Article a1 = (Article)s.CreateObject(typeof(Article));
        a1.Title = "Car accidents";
        a1.Date = new DateTime(1998, 3, 5);
        a1.Author = Anonymous;
        a1.References.Add(new Reference("http://www.crash.com/"));
        a1.References.Add(new Reference("ftp://www.crash.com/"));
        a1.Comments.Add(new Comment(Tyler,"No comments..."));

        Article a2 = (Article)s.CreateObject(typeof(Article));
        a2.Title = "Corporations";
        a2.Date = new DateTime(1998, 3, 1);
        a2.Author = Anonymous;
        a2.Comments.Add(new Comment(Tyler,"You'd look deeper."));

        Article a3 = (Article)s.CreateObject(typeof(Article));
        a3.Title = "Survival Instinct";
        a3.Date = new DateTime(1998, 3, 3);
        a3.Author = Tyler;
        a3.SeeAlso.Add(a1);
        a3.SeeAlso.Add(a2);

        Article a4 = (Article)s.CreateObject(typeof(Article));
        a4.Title = "Anarchy";
        a4.Date = new DateTime(1998, 3, 7);
        a4.Author = Tyler;
        a4.SeeAlso.Add(a2);
        a4.SeeAlso.Add(a3);

        s.Commit();
      }
      Console.WriteLine("  OK.");
    }

    static void QueryData()
    {
      Console.WriteLine("Querying data...");
      using (Session s = domain.CreateSession()) 
      {
        s.BeginTransaction();

        string text;
        Query q;
        QueryResult r;
        ValueTypeQueryResult vr;

        Console.WriteLine();
        Console.WriteLine("> All articles which author's name starts with 'Tyler':");
        text = "Select Article instances where {Author.Name} like 'Tyler%'";
        Console.WriteLine("  Query: \"{0}\"", text);
        Console.WriteLine("> Or the same, but by another way:");
        text = "Select Article instances require $root.Author[{Name} like 'Tyler%']";
        Console.WriteLine("  Query: \"{0}\"", text);
        Console.WriteLine("> Last query uses 'inner join', so it should work faster.");

        q = new Query(s, text);
        r = q.Execute();
        Console.WriteLine("  Result: {0} objects.", r.Count);
        foreach (Article a in r)
          Console.WriteLine("    {0}", a.Title);
        Console.Write("Press enter to continue... "); Console.ReadLine();


        Console.WriteLine();
        Console.WriteLine("> Authors ordered by the publishing date. Unpublished authors go first "+
                          "('let' results in 'left join' here):");
        text = "Select Author instances let $root.Articles $A order by {$A.Date}";
        Console.WriteLine("  Query: \"{0}\"", text);

        q = new Query(s, text);
        r = q.Execute();
        Console.WriteLine("  Result: {0} objects.", r.Count);
        foreach (Author a in r)
          Console.WriteLine("    {0}", a.Name);
        Console.Write("Press enter to continue... "); Console.ReadLine();


        Console.WriteLine();
        Console.WriteLine("> Articles published after the specified date, but containing articles "+
                          "that were published before that date in SeeAlso:");
        text = "Select Article instances where {Date}>@Date and "+
               "{(Article)SeeAlso[{Date}<@Date].count}>0";
        Console.WriteLine("  Query: \"{0}\"", text);

        q = new Query(s, text);
        q.Parameters.Add("@Date", new DateTime(1998, 3, 4));
        r = q.Execute();
        Console.WriteLine("  Result: {0} objects.", r.Count);
        foreach (Article a in r)
          Console.WriteLine("    {0}", a.Title);
        Console.Write("Press enter to continue... "); Console.ReadLine();


        Console.WriteLine();
        Console.WriteLine("> Querying the whole collection: checks Article.SeeAlso for object "+
                          "of type Article:");
        text = "Select (Article)Article.SeeAlso instances";
        Console.WriteLine("  Query: \"{0}\"", text);

        q = new Query(s, text);
        r = q.Execute();
        Console.WriteLine("  Result: {0} objects.", r.Count);
        foreach (Article a in r)
          Console.WriteLine("    {0}", a.Title);
        Console.Write("Press enter to continue... "); Console.ReadLine();


        Console.WriteLine();
        Console.WriteLine("> Articles having references to FTP sites:");
        text = "Select Article instances where {References[{URL} like 'ftp://%'].count} > 0";
        Console.WriteLine("  Query: \"{0}\"", text);

        q = new Query(s, text);
        r = q.Execute();
        Console.WriteLine("  Result: {0} objects.", r.Count);
        foreach (Article a in r)
          Console.WriteLine("    {0}", a.Title);
        Console.Write("Press enter to continue... "); Console.ReadLine();


        Console.WriteLine();
        Console.WriteLine("> Comments by Tyler Durden ordered by Article date:");
        text = "Select Article.Comments values where 'Tyler Durden' = any{Author.Name} "+
               "order by {parent.Date}";
        Console.WriteLine("  Query: \"{0}\"", text);

        q = new Query(s, text);
        vr = q.ExecuteValueTypeQueryResult();
        Console.WriteLine("  Result: {0} values.", vr.Count);
        foreach (ValueTypeQueryResultEntry entry in vr)
          Console.WriteLine("    {0}", ((Comment)entry.Value).Body);
        Console.Write("Press enter to continue... "); Console.ReadLine();


        Console.WriteLine();
        Console.WriteLine("> Quotes with length > 50:");
        string lenFunc = s.DriverInfo.Type=="MSSQL" ? "len" : "length";
        text = "Select Author.Quotes values where "+lenFunc+"({Body}) > 50";
        Console.WriteLine("  Query: \"{0}\"", text);

        q = new Query(s, text);
        vr = q.ExecuteValueTypeQueryResult();
        Console.WriteLine("  Result: {0} values.", vr.Count);
        foreach (ValueTypeQueryResultEntry entry in vr)
          Console.WriteLine("    {0}", ((Quote)entry.Value).Body);

        s.Commit();
      }
    }
  }
}