views:

478

answers:

4

There are a couple of resources on the Internet describing preview 2 of subsonic with Astoria :

http://theruntime.com/blogs/jaykimble/archive/2008/11/18/quotsubsonicquot-for-services-found-subsonic-3--ado.net-data-services.aspx

and working sample at

http://code.msdn.microsoft.com/SubSonicForADONETDS

I applied all respective changes to subsonic tt(s) , however didn't manage to make MSDN project work. After eliminating :

a) Astoria didn't like private DB() { } in QuerySurface.tt , so I blindly made constructor public

b) Not sure how to generate compound primary key

<# if(EnableForUseWIthAstoria) {
#> [System.Data.Services.Common.DataServiceKey("<#=pk#>")] <# }#>

results in

[System.Data.Services.Common.DataServiceKey("")]

instead of

[System.Data.Services.Common.DataServiceKey("OrderID", "ProductID")]

so just excluded the table.

The current obstacle

        var q = from cust in ctx.Customers
                where cust.CustomerID == "ROMEY"
                select cust;

        Customers c = q.First();

results in exception: Resource not found for the segment 'Customers'

Has anyone tried that or knows another the latest and greatest sample existence ?

A: 

Yes, I checked in a version of ss3 with the IUpdatable interface, and inherited the DB query surface class from an UpdatableDatabase class. I also included a starter test project for it. The nice part is that you can construct a DB class with a Uri, and start working against a service. But it is not part of the current core, it requires a new class and some rearranging, plus minor template changes. I think this is one of those areas where people will keep reinventing this thing and not build on previous work. There are several changes I've wanted to get into the project but they not making it, like multiple databases setup at runtime, ado.net services, etc. I think I will have to permanently branch my own version.

This issue has an attachment showing the UpdatableDatabase class.

http://code.google.com/p/subsonicthree/issues/detail?id=30

I added this to SubSonicClasses.ttinclude:

public string PrimaryKey { get { return Utilities.CleanUp(this.Schema.GetTablePrimaryKey(TableSchema, TableNameRaw)); } }

...

[System.Data.Services.Common.DataServiceKey("<#=PrimaryKey #>")]

I see I cheated with the OrderDetails in Northwind and added the second key by directly editing the file. You could easily write a method like this in DatabaseSchema.ttinclude:

public string[] GetTablePrimaryKeys(string tableSchema, string tableName)

and build up the correct string.

P a u l
Is starter test project available for download ? Did you refer to http://code.google.com/p/subsonicthree/source/browse/ , I can't see any branches.
MicMit
It appears to have been completely wiped out from source control. I can provide a link to my version later today. It has the template changes, etc.
P a u l
A: 

I don't know if I can zip up a solution and give it out since there is the subsonic license involved. It's not subsonic proper, and is about 2 months old (out of date). I just ran the project to test that it was still working and it is. Here are the steps to do this:

Use the UpdatableDatabase class referred to above. Then derive DB from it (put this in the template):

public partial class DB : UpdateableDatabase

UpdatableDatabase.cs has to be in with the generated classes or it won't work, since it needs to GetType() on the table classes.

The service is merely a service project with this class:

using System.Data.Services;
using Northwind;

namespace NorthwindService
{
    [System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults=true)]
    public class Northwind: DataService<DB>
    {
        // This method is called only once to initialize service-wide policies.
        public static void InitializeService(IDataServiceConfiguration config)
        {
            config.SetEntitySetAccessRule("*", EntitySetRights.All);
            config.UseVerboseErrors = true;
        }
    }
}

The service part of web.config is easy:

  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
  </system.serviceModel>

Then for the test project, add a service reference to the service. I took the test code from the astoria project I think, it's been a while:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using WcfClientTest.NorthwindService;

namespace WcfClientTest
{
    /// <summary>
    /// Summary description for WcfTest
    /// To run these tests, load this project, and somehow get a server running at the URI. 
    /// This can be done by updating the service reference to start the development server.
    /// </summary>
    [TestClass]
    public class WcfTest
    {
        private string baseURI = "http://127.0.0.1:49649/Northwind.svc";
        private DB ctx;

        /// <summary>
        /// Sets up test.
        /// </summary>
        [TestInitialize]
        public void SetUp()
        {
            ctx = new DB(new Uri(baseURI));
        }

        [TestCleanup]
        public void Cleanup()
        {
        }

        [TestMethod]
        public void Select_Simple_With_Variable()
        {
            int categoryID = 5;
            IQueryable<Product> result = from p in ctx.Products
                                         where p.CategoryID == categoryID
                                         select p;

            List<Product> products = result.ToList();
            Assert.AreEqual(7, products.Count());
        }

        [TestMethod]
        public void TestAddNew()
        {
            // add customer
            var c = new Customer
                        {
                            CustomerID = "XXXXX",
                            ContactTitle = "Prez",
                            Country = "USA",
                            ContactName = "Big Guy",
                            CompanyName = "Big Guy Company"
                        };
            ctx.AddToCustomers(c);
            ctx.SaveChanges();

            IQueryable<Customer> qCustomer = from cust in ctx.Customers
                                             where cust.CustomerID == "XXXXX"
                                             select cust;

            Customer c2 = qCustomer.FirstOrDefault();

            Assert.AreEqual("XXXXX", c2.CustomerID);

            if (c2 != null)
            {
                ctx.DeleteObject(c2);
            }
            ctx.SaveChanges();

            IQueryable<Customer> qCustomer2 = from cust in ctx.Customers
                                              where cust.ContactName == "Big Guy"
                                              select cust;
            // Returns null if the row isn't found.
            Customer c3 = qCustomer2.SingleOrDefault();
            Assert.AreEqual(null, c3);
        }
    }
}

That's all I have, it's not hard to put together. Right now it's a solution in search of a problem, but I intend to use it sometime. It would be possible to bypass subsonic entirely, and use the IQToolkit directly, and along with some T4 templates have a pretty nice system.

P a u l
Thanks for all info. Trouble is the most recent checkout from SVN doesn't compile straightforwardly , so I use alpha zip dll. Looks like your sample used newer methods , I had to change back ITable tbl = db.FindTable(typeof(T).Name);// ITable tbl = db.FindTableByClassName(typeof(T).Name);and etc... I made everything compile , but the same error from Data Service :Resource not found for the segment 'Customers'.Perhaps,I'll be waiting for another complete sample to appear on the Internet wrapped as sln.
MicMit
It will compile, but I had to fiddle with it for a few minutes. The 'FindTableByClassName' was refactored into 'FindTable'. I think you can track down that error using the debugger. I certainly understand why you would like a sample project. I can zip it up but I don't know how to deliver it...
P a u l
A: 

Here is a patch for the IUpdatable interface and the required template changes. I'm 99% sure this won't go into the final project, but at least you can see how I did it.

http://code.google.com/p/subsonicthree/issues/detail?id=52

P a u l
Out of curiosity , you used original sample from MSDN for UpdateableDatabase.cs and there : public abstract class UpdateableDatabase: IUpdatable, IQuerySurfacewhereas in original : public partial class DB : IUpdatable was a necessity or design choice.
MicMit
The original file was SubSonicIUpdateable.cs. I did this work about 3 months ago and I don't remember why I did that, but I think it works either way. I just reviewed the code today to make sure the tests were still passing. I have a sample running the the latest head subsonic3 revision.
P a u l
+1  A: 

See this issue for a demo template for data services:

http://code.google.com/p/subsonicthree/issues/detail?id=53

P a u l