Saturday, December 26, 2009

videoWe are furiously working on our ES2010 Prototype which is quickly turning into the “real deal”. The first thing we wanted to address was performance and have squeezed out a ton more horsepower, the performance is excellent. Secondly, we wanted to enhance our collections by implementing IList<T> which we have done. There is no longer a need to convert our collection classes to List<T> collections to gain access to it’s powerful API. Our collections and List<T> are essentially one and the same.

This means you have a whole new set of functionality at your disposal (using the newer .NET syntax) on our collections, including filtering, which is shown in the (hastily put together) video, you can view the video by clicking on the image on the left.

Here’s the way you can filter a collection in ES2010. The “coll” variable is an EntitySpaces collection object.

coll.Filter = coll.AsQueryable().Where(d => d.FirstName.EndsWith("2")).OrderByDescending(d => d.FirstName); 

In this case we are filtering an EntitiySpaces collection so that it only shows only FirstName’s that end with the number “2” and we also sort them in descending order by FirstName as well.

You can also now perform operations like this (shown below) on your collections, granted this example doesn’t make much sense but it does show the functionality.

int? max = coll.Max(ent => ent.EmployeeID); // Find the highest EmployeeID

We are working very hard and preserving the API too. One of the main changes is that we now no longer use DataTables/DataRows under the hood as a storage mechanism, however you really shouldn’t notice that. Our Custom Property support will now be attribute based and extremely simple to use. Serialization is going to even better (and it’s already fantastic in ES2009). Binary serialization will now be tiny now that we no longer use DataTable’s and we will be adding full JSON serialization support as well. There is just so much more to come and we can’t wait to show you more.

Forgive this hastily put together video, we will be doing a series of these video’s so keep your eyes on the blog.

EntitySpaces

From Mobile Devices to large scale enterprise solutions in need of serious transaction support, EntitySpaces can meet your needs. Whether you’re writing an ASP.NET application with Medium Trust requirements, a Silverlight/WCF application, a Mono application, or a Windows.Forms application, the EntitySpaces architecture is there for you. EntitySpaces is provider independent, which means that you can run the same binary code against any of the supported databases. EntitySpaces is available in both C# and VB.NET. EntitySpaces uses no reflection, no XML files, and sports a tiny foot print of less than 200k. Pound for pound, EntitySpaces is one tough, dependable .NET architecture.

EntitySpaces LLC
Persistence Layer and Business Objects for Microsoft .NET
http://www.entityspaces.net

posted on Saturday, December 26, 2009 8:15:59 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]
 Saturday, December 12, 2009

This is our final release for ES2009, the version number is 2009.2.1214.0. The Developer version and Source Version are available now. The trial version is now available as well. Watch for an announcement on our twitter account if you are waiting on the new Trial version.

Release Notes:

  • The DynamicQuery API “Between” bug has been fixed.
  • The VB.NET Hierarchical Model Equals vs IsNot bug has been fixed.
  • All SQL CE providers now correctly support the SQL TOP syntax.
  • There was a bug that would sometimes occur in the Microsoft SQL Contains clause. This has been fixed.
  • We tweaked the IDataErorrInfo so that it shouldn’t matter if column names or property names are passed in.
  • Modified SqlClientProvider.Shared.BuildDynamicInsertCommand to ignore modifications to dis-allowed columns, such as Computed, Concurrency, and AutoIncrement.
  • Added a mapping entry for the Microsoft SQL HierarchyId data type.
  • Added an overload for SetColumn() which should be used when setting the values of virtual properties that exist in the underlying DataTable. The usage is covered in this blog post. We plan to make big improvements our virtual column handling in ES2010. The signature is as follows, you pass in true as the last parameter for virtual properties.

          public void SetColumn(string columnName, object Value, bool isVirtualColumn)
  • Greatly improved our Schema/Catalog handling in the DynamicQuery API making cross schema/catalog joins much better now.
  • During an insert all columns that are either computed or that have defaults are now returned (currently only implemented for Microsoft SQL Server). We will revisit this for all providers in ES2010.
  • Greatly improved the power of the ON clause of a JOIN statement. The ON clause can now fully parse anything that can be used in a Where clause. This means the full Where syntax can now be used in the ON clause of a JOIN statement. This is true for all providers accept for Microsoft Access which requires extra parenthesis be paced around each join condition. We will revisit this functionality for MS Access in ES2010.
  • Due to our relocation to a new dedicated hosting server some of our links on the Windows “EntitySpaces 2009” menu were no longer valid. This was also true for “Forums” link on the “Whats New” tab, these have been fixed.
  • Added WithNoLock support. This is currently support for Microsoft SQL Server only (Locking hints are vastly different on all database systems).

    OrderQuery oq = new OrderQuery("o");
    OrderItemQuery oiq = new OrderItemQuery("oi");

    oq.Select(oq.CustID, oq.OrderDate, "<sub.OrderTotal>");
    oq.From
        (
            oiq.Select(oiq.OrderID,
                (oiq.UnitPrice * oiq.Quantity).Sum().As("OrderTotal"))
                .GroupBy(oiq.OrderID)
        ).As("sub");
    oq.InnerJoin(oq).On(oq.OrderID == oiq.OrderID);

    OrderCollection collection = new OrderCollection();
    oq.es.WithNoLock = true; // <== NEW
    collection.Load(oq);

    Notice that even though many query objects are being used you only need to set WithNoLock to true for the parent or main query object. The SQL generated is as follows:

    SELECT o.[CustID],o.[OrderDate],sub.OrderTotal 
    FROM
    (
       SELECT oi.[OrderID],SUM((oi.[UnitPrice]*oi.[Quantity])) AS 'OrderTotal' 
       FROM [OrderItem] oi WITH (NOLOCK)
       GROUP BY oi.[OrderID]
    ) AS sub
    INNER JOIN [Order] o WITH (NOLOCK)
    ON o.[OrderID] = sub.[OrderID]
     

EntitySpaces

From Mobile Devices to large scale enterprise solutions in need of serious transaction support, EntitySpaces can meet your needs. Whether you’re writing an ASP.NET application with Medium Trust requirements, a Silverlight/WCF application, a Mono application, or a Windows.Forms application, the EntitySpaces architecture is there for you. EntitySpaces is provider independent, which means that you can run the same binary code against any of the supported databases. EntitySpaces is available in both C# and VB.NET. EntitySpaces uses no reflection, no XML files, and sports a tiny foot print of less than 200k. Pound for pound, EntitySpaces is one tough, dependable .NET architecture.

EntitySpaces LLC
Persistence Layer and Business Objects for Microsoft .NET
http://www.entityspaces.net

posted on Saturday, December 12, 2009 2:47:24 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]
 Sunday, December 06, 2009

This question has been brought up recently so we created a sample to demonstrate how this can be accomplished. When we refer to Virtual Properties we mean properties that you manually add to your Custom classes (as opposed those that are created from your database schema during code generation and wind up in your generated classes). In this example we are going to create two Virtual Properties, one that is backed by a private string variable and the other backed by a column in the underlying DataTable.

Adding the Virtual Properties to the Custom Class (Your Main Entity)

Notice the two properties MyCustomProperty and MyCustomPropertyFullName

namespace BusinessObjects
{
    public partial class Employees : esEmployees
    {
        // Virtual Property backed by a private string
        public string MyCustomProperty
        {
            get { return myCustomProperty; }
            set { myCustomProperty = value; }
        }
        private string myCustomProperty;

        // Virtual Property backed by a Column in the underlying DataTable
        public string MyCustomPropertyFullName
        {
            get { return this.GetSystemString("FullName"); }
            set { this.SetColumn("FullName", value, true); } // New Method
        }

        // Makes sure these properties show up when binding ...
        protected override List<esPropertyDescriptor> GetLocalBindingProperties()
        {
            List<esPropertyDescriptor> props = new List<esPropertyDescriptor>();

            props.Add(new esPropertyDescriptor(this, "MyCustomProperty", typeof(string)));
            props.Add(new esPropertyDescriptor(this, "MyCustomPropertyFullName", typeof(string)));

            return props;
        }

        // We need to do this for the deserialization process (more on this later)
        public override void AddNew()
        {

            // only needed if for the DataTable backed column
            base.AddNew();

            if (!this.Table.Columns.Contains("FullName"))
            {
                this.Table.Columns.Add("FullName", typeof(System.String));
            }
        }

    }
}

Typically, you don’t allow users edit virtual properties. In this example we are allowing it and this is the reason we needed to override AddNew. The reason we need to do this is that when we deserialize from the client back to the server you do not get to create the EmployeesCollection, instead the deserialization process does this. So, we overload AddNew() to make sure our underlying DataTable contains the DataColumn to hold our “FullName” value coming back from the client side. In ES2010 we are going to take a hard look at this and make this area easier. With all of the new emphasis on Silverlight 4.0 we want to make sure our proxies and serialization logic are the best and easiest they can be. However, if you are not going to allow users to edit “Virtual Properties” on the client there is no need to override AddNew.

The above code in “red” is new and will be the next maintenance release. The allows you to set virtual columns in the DataTable and not have them marked as dirty which causes the provider to try to save it. However, you can do this now without the new method though the code for that is not shown here.

Adding the Virtual Properties to the Proxies

The Server Side Proxy Class

When we generated the server and client proxies we made sure to check the “CompactXml” checkbox. This makes the XML sent over the wire much more compact. Our “Compact Xml” names each field a0, a1, a2 and so on (in the XML only). This makes the XML so much smaller than using the actual property names. However, it doesn’t effect your property names whatsoever, you still always work with your nice names in code. We recommend that you start your Virtual Properties at “a1000” and then you will never get into to trouble, that is, unless you have 1000 columns in your table in which case you probably have bigger problems.

Our server side and client side proxies are partial classes, so you can easily add more properties to them. Below is the server proxy partial class that we created to house our two addition properties. This ensures that you never hand edit the generated proxies.

namespace BusinessObjects
{
    public partial class EmployeesProxyStub
    {
        [DataMember(Name = "a1000", Order = 1000, EmitDefaultValue = false)]
        public System.String MyCustomProperty
        {
            get
            {
                return this.Entity.MyCustomProperty;
            }
            set { this.Entity.MyCustomProperty = value; }
        }

        [DataMember(Name = "a1001", Order = 1001, EmitDefaultValue = false)]
        public System.String MyCustomPropertyFullName
        {
            get
            {
                return this.Entity.MyCustomPropertyFullName;
            }
            set { this.Entity.MyCustomPropertyFullName = value; }
        }
    }
}

The Client Side Proxy Class

If you are deserializing from the server side proxies into the client side proxies you want to use the same signature for the the properties in the client side proxy.

namespace Proxies
{
    public partial class EmployeesProxyStub
    {
        [DataMember(Name = "a1000", Order = 1000, EmitDefaultValue = false)]
        public System.String MyCustomProperty
        {
            get
            {
                return _myCustomProperty;
            }
            set
            {
                this.SetDirty();
                this._myCustomProperty = value;
                this.RaisePropertyChanged("MyCustomProperty");
            }
        }
        private System.String _myCustomProperty;

        [DataMember(Name = "a1001", Order = 1001, EmitDefaultValue = false)]
        public System.String MyCustomPropertyFullName
        {
            get
            {
                return _myCustomPropertyFullName;
            }
            set
            {
                this.SetDirty();
                this._myCustomPropertyFullName = value;
                this.RaisePropertyChanged("MyCustomPropertyFullName");
            }
        }
        private System.String _myCustomPropertyFullName;
    }
}

One Minor Gotcha

The way our logic is setup the esRowState property of the proxies must be the last property serialized because it determines the row state. Therefore, what we did for this example was to hand edit both the generated proxies (server and client) and change the esRowState to the name and order of 10,000 to make sure it’s last. Here are the hand edits …

[DataMember(Name = "a10000", Order = 10000)]
public string esRowState
{
    get { return this._esRowState; }
    set { this._esRowState = value; }
}

However, we have already made changes in our template(s) so that our next maintenance release (due out very soon) will always set the esRowState to the name and order of 10,000. If you want to make these hand edits to your templates you can do so very easily and simply regenerate. You would need to do this in both proxy templates if you are using both the server and client proxies.

BEFORE

<%if(WcfSupport){%>[DataMember(Name="<%=CompactXML ? "a" + compactXmlIndex++.ToString() : "esRowState"%>"<%if(WcfOrder){%>, Order=<%=(++lastOrdinal).ToString()%><%}%>)]<%}%>
public string esRowState
{
    get { return TheRowState;  }
    set { TheRowState = value; }
}<%}%>

 

AFTER

<%if(WcfSupport){%>[DataMember(Name="<%=CompactXML ? "a10000" : "esRowState"%>"<%if(WcfOrder){%>, Order=10000<%}%>)]<%}%>
public string esRowState
{
    get { return TheRowState;  }
    set { TheRowState = value; }
}<%}%>

 

Finally, the test, does it work?

First, this code is for demonstration purposes only. You never have to use our esDataContractSerializer manually, in fact, you should not be using it unless you absolutely have to. Instead, just pass our proxies to and from your WCF methods as normal parameters and the serialization will happen normally. However, the code below uses our esDataContractSerializer so you can try this in your own code quickly without having to build the services and test it all. In this example we serialize from the server proxies (found in your generated classes) to the client side proxies and back again. If you were using the server proxies on both sides of the conversation you wouldn’t need to generate or mess with the client side proxies of course.

It’s fun to run the code below and look at the XML that is sent back and forth.

private void button1_Click(object sender, EventArgs e)
{
    try
    {
        EmployeesCollection coll = new EmployeesCollection();
        EmployeesQuery q = new EmployeesQuery("e");

        q.SelectAllExcept(q.Notes, q.Photo); // We want all columns but the Notes and Photo
        q.Select((q.LastName + ", " + q.FirstName).As("FullName"));  // Fills our DataTable backed property
        q.es.Top = 3;

        if (coll.Load(q))
        {

            // Change our string back properties
            foreach (Employees emp in coll)
            {
                emp.MyCustomProperty = "Test";
            }

            // Create Our Proxy Stubb
            BusinessObjects.EmployeesCollectionProxyStub server = new BusinessObjects.EmployeesCollectionProxyStub(coll, false);

            // Serialize it into a string and return this string to Silverlight
            string xml = esDataContractSerializer.ToXml(server);

            using (StreamWriter sw = File.CreateText("C:\\query.xml"))
            {
                sw.Write(xml);
                sw.Flush();
                sw.Close();
            }

            // Deserialize the string above into our Client side proxy
            Proxies.EmployeesCollectionProxyStub client = esDataContractSerializer.FromXml(xml, typeof(Proxies.EmployeesCollectionProxyStub))
                as Proxies.EmployeesCollectionProxyStub;

            // Set a property and notice that esRowState goes to Modified
            client.Collection[0].LastName = "CrazyDude";
            client.Collection[0].MyCustomProperty = "MyCustomProperty";
            client.Collection[0].MyCustomPropertyFullName = "Griffin, Mike";

            // Serialize our client side proxy into xml and send it to the server
            xml = esDataContractSerializer.ToXml(client);

            // Deserialize it on the server, the esRowState is modifed as we would expect
            BusinessObjects.EmployeesCollectionProxyStub server1 =
                esDataContractSerializer.FromXml(xml, typeof(BusinessObjects.EmployeesCollectionProxyStub))
                as BusinessObjects.EmployeesCollectionProxyStub;

            // Now save the Entity
            server1.GetCollection().Save();
        }
    }
    catch (Exception ex)
    {

    }
}

The XML

Notice that our two custom properties are at a1000, and a1001 and we have changed esRowState to be a10000.

<EmployeesCollection xmlns="http://tempuri.org/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <Collection>
        <Employees>
          <a0>1</a0>
          <a1>CrazyDude</a1>
          <a2>AAAA</a2>
          <a3>Sales Representative</a3>
          <a4>Ms.</a4>
          <a5>1948-12-08T00:00:00</a5>
          <a6>1992-05-01T00:00:00</a6>
          <a8>Seattle</a8>
          <a9>WA</a9>
          <a10>78890</a10>
          <a11>USAa</a11>
          <a12>(206) 555-9857</a12>
          <a13>5467</a13>
          <a16>70272</a16>
          <a17>http://accweb/emmployees/davolio.bmp</a17>
          <a1000>Test</a1000>
          <a1001>CrazyDude, AAAA</a1001>
          <a10000>Unchanged</a10000>

        </Employees>
        <Employees>
          <a0>2</a0>
          <a1>Fuller</a1>
          <a2>tttt</a2>
          <a3>Vice President, Sales</a3>
          <a4>Ms.</a4>
          <a5>1953-02-19T00:00:00</a5>
          <a6>1992-08-14T00:08:00</a6>
          <a7>908 W. Capital Way</a7>
          <a8>Tacoma</a8>
          <a9>WA</a9>
          <a10>98401</a10>
          <a11>USA</a11>
          <a12>(206) 555-9482</a12>
          <a13>3457</a13>
          <a16>99</a16>
          <a17>http://accweb/emmployees/fuller.bmp</a17>
          <a1000>Test</a1000>
          <a1001>Fuller, tttt</a1001>
          <a10000>Unchanged</a10000>

        </Employees>
        <Employees>
          <a0>3</a0>
          <a1>Spaces</a1>
          <a2>tttt</a2>
          <a3>Sales Representative</a3>
          <a4>Ms.</a4>
          <a5>1963-08-30T00:00:00</a5>
          <a6>1992-04-01T00:00:00</a6>
          <a7>722 Moss Bay Blvd.</a7>
          <a8>Kirkland</a8>
          <a9>WA</a9>
          <a10>98032</a10>
          <a11>USA</a11>
          <a12>(206) 555-3412</a12>
          <a13>3355</a13>
          <a16>2</a16>
          <a17>http://accweb/emmployees/leverling.bmp</a17>
          <a1000>Test</a1000>
          <a1001>Spaces, tttt</a1001>
          <a10000>Unchanged</a10000>

        </Employees>
    </Collection>
</EmployeesCollection>

Summary

This was an extremely valuable exercise for us and revealed a few shortcomings when it comes to serialization virtual properties. Is is possible to implement your code without the new method in red above but that code is not shown here. We are hoping most of you desiring this functionality will be upgrading to our upcoming maintenance release. Also, remember, you can generate entities from views and in views you can create columns that are virtual and not based on database columns at all. This would make a lot of the above work a mute exercise with the caveat that views cannot be saved (easily) back to the database.

Our proxies are very important to future of EntitySpaces and they even run down inside the browser along with our DynamicQueries inside of Silverlight (under the browser) and we will be stepping back to see how we can make them far more powerful and easy to expand in ES2010. However, our next maintenance release will certainly make the above code a no brainer.

EntitySpaces

From Mobile Devices to large scale enterprise solutions in need of serious transaction support, EntitySpaces can meet your needs. Whether you’re writing an ASP.NET application with Medium Trust requirements, a Silverlight/WCF application, a Mono application, or a Windows.Forms application, the EntitySpaces architecture is there for you. EntitySpaces is provider independent, which means that you can run the same binary code against any of the supported databases. EntitySpaces is available in both C# and VB.NET. EntitySpaces uses no reflection, no XML files, and sports a tiny foot print of less than 200k. Pound for pound, EntitySpaces is one tough, dependable .NET architecture.

EntitySpaces LLC
Persistence Layer and Business Objects for Microsoft .NET
http://www.entityspaces.net

posted on Sunday, December 06, 2009 2:53:37 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]