Skip to content

Azure Table Storage POCO wrapper for secondary indexes, full text search and unsupported types

Notifications You must be signed in to change notification settings

AversaConsulting/Alte

Repository files navigation

alte indexed poco azure tables

Tiny Embedded .NET NoSQL Style Database with cloud storage in Azure Table Storage with massive scaleability

Download from NuGet - search for ALTE

Download this project for demo in C#

Visit developer at www.aversa.co.uk

  • .NET Objects are stored in Azure Table Storage

  • Stores one property in one column on Azure for full compatibility and simplicity

  • Can store Decimal/Currency/TimeSpan etc. type fields not normally supported in Table Storage

  • Can store larger byte arrays or strings over multiple columns automatically

  • Any number of properties can be indexed for lightning quick retreival

  • Simple strongly typed fluent query syntax - easier than LINQ - then use client LINQ after!

  • Authomatically uses an index on the query and will warn you if you're not using an index in the output window

  • Tables (Objects) can be full text indexed

  • Pass in a search phrase to search the full text index

  • Easy to read automatic time sequential IDs - similar to GUIDs but more user friendly and shorter - or use several other ID types or roll your own

  • Optimistic concurrency built in

  • Simple and easy to use blob storage utilities built in

  • Other utilites included - Randomise lists, Re-indexing, Backup of Table and Blobs

  • Includes an ASP.NET session provider - although work is still needed on this to clear old session data, it is fully working

  • Multi-tenant database connection methods allow more than one "database" per table store

  • USES: -- Multi-tenant apps -- Large scale apps

  • In use on our multi tennant e-commerce platform - e.g. www.woodstyle.co.uk

  • In use currently on large scale classified selling platform - e.g. www.advertisedelsewhere.co.uk

  • In use on hotel booking systems - e.g. www.hengardirect.co.uk

See how easy it is to get going!

    static void Main(string[] args)
            {

                Console.WriteLine("Open our database");

                var DB = new Alte.AlteSession("altedemo", "2BQX+KxHC7KbEX5Dd3wFOTV+HHsvmpnsaSJ2/H1Evd7i41tScEP1VFuvB/gd+Jg4iaPfwlhyl2cNhtxip1fNhA==", "mydemo");
                // we are creating a connection to altedemo azure storage account. V1 or V2 is fine, V2 can be cheaper. The last parameter allows to to prefix
                // our tables to in all essence have multiple databases within one storage account. This is great for multi tenant apps - but obviously you
                // will load the account more this way. 

                DB.CreateStore<Person>();
                // this isn't 100% necessary but good practice

                DB.RebuildIndexes<Person>();
                // if you change object structure - ESPECIALLY indexes - run this to re-index the table


                Person newperson;

                Console.WriteLine("Try to load person record with ID DEMO");

                newperson = DB.GetByID<Person>("DEMO");
                //try and load our person from the database with ID "DEMO"

                if (newperson is null)
                {
                    Console.WriteLine("We haven't got a record with ID DEMO, so lets create and save");

                    newperson = new Person(DB);
                    newperson.ID = "DEMO"; //normally leave this or use one of the standard options - but for this demo we can use later

                }
                else
                {
                    Console.WriteLine("We got our record!");
                }

                Console.WriteLine("Changing Properties");

                newperson.Email = "testbod@alte.co.uk";
                newperson.FirstName = "Jack";
                newperson.LastName = "Whitfield";
                newperson.Title = "Mr";
                newperson.ProfileNotes = "I am a very proficient .NET programmer - more VB than C#, but pretty good at HTML and JavaScript too!";
                newperson.HourlyRate = 50.55M;
                newperson.ServiceLength = new TimeSpan(365, 0, 0, 0, 0);
                newperson.PersonType = PersonTypes.Freelancer;
                newperson.Save();


                //now get record by various methods!

                //individual record by ID - will return the record or null
                var p1 = DB.GetByID<Person>("DEMO");

                //query of records by property name - returns a list (may be empty!). Will automatically use an indexed property
                //if available, else will fall back to Azure Table queries
                var p2_list = DB.Query<Person>().Where(nameof(Person.Email), QueryOperand.Equal, "testbod@alte.co.uk").Result();

                //we can get more complicated
                var p3_list = DB.Query<Person>().Where(nameof(Person.Email), QueryOperand.Equal, "testbod@alte.co.uk").Or(nameof(Person.LastName), "Whitfield").Result();

                //we are using nameof to keep it type safe - but you can just use the field name directly as a string
                //and by default the query is an equals
                var p4_list = DB.Query<Person>().Where("Email", "testbod@alte.co.uk").Result();

                //make a change in our list
                p4_list[0].LastName = "Whittlefields";
                p4_list[0].Save();


                //query by full text. Full text indexes can also store specified fields if you'd use them to save retrieving the full item
                //**NOTE** that the properties saved in the index are LOWER CASE regardless of case in the object
                List<FullTextResult> i1_list = DB.GetFullTextResults<Person>("html");
                Console.WriteLine("Got FTS results from FTS :" + i1_list[0].ID + " - " + i1_list[0].Properties["email"]);

                //get the full object results from the full text results
                var p5_list = DB.GetByFullTextResult<Person>(i1_list);
                Console.WriteLine("Got record from FTS list :" + p5_list[0].ID + " - " + p5_list[0].LastName);

                Console.WriteLine("Press return to exit");
                Console.ReadLine();
            }
        }


    class Person : Alte.AlteObject
    {
            public Person() { }

            public Person(Alte.AlteSession alteSession) : base(alteSession)
            { }

            public string FirstName { get; set; }
            public string LastName { get; set; }
            public string Title { get; set; }

            //normal index, but store with the full text search
            [Alte.Index(), Alte.FTSstore()]
            public string Email { get; set; }

            //full text search index
            [Alte.FTSindex()]
            public string ProfileNotes { get; set; }

            //DateTime is dealt with properly meaning a minvalue (or null) is correctly stored and returned
            public DateTime DateOfBirth { get; set; }

            //Types not supported normally in Azure Tables
            public decimal HourlyRate { get; set; } // Stored internally as integer / 10000
            public TimeSpan ServiceLength { get; set; } // Stored internally as ticks
            public List<string> Skills {get;set;} // lists stored internally as JSON string
            public PersonTypes PersonType { get; set; }

            }

        enum PersonTypes
        {
            Customer,
            Freelancer
        }

About

Azure Table Storage POCO wrapper for secondary indexes, full text search and unsupported types

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages