From LINQ team to App Framework on Silverlight team

A while ago (October last year), I moved from C# team to the "UI Frameworks" team inside the .NET Developer Platform team. C# team is where LINQ was incubated and large portions of LINQ were productized: LINQ to Objects, LINQ to SQL and C# 3.0 to be precise. So it was with mixed emotions that I left. Why mixed? Because the team and the project that I moved to are also very exciting. Now that I have been there for a while, I can start talking a bit about it though we would rather build something for a preview before I talk :-)

First about the team - the UI Frameworks team drives two big pieces - ASP.NET and client components like WinForms and Silverlight controls. The team covers a fair amount of ground beyond the Data Access Layer all the way to the final presentation of data. This is a very fertile ground for innovation that raises some very interesting topics for future discussions.

LINQ to SQL has been handed off to my previous team - Data Programmability team that owns a variety of ADO.NET technologies. However, given my passion and the years I spent on LINQ and LINQ to SQL in particular, I will likely continue to write about it.

Cheers!

Dinesh

 

Lifetime of a LINQ to SQL DataContext

One of the frequently asked questions is about the lifetime of a DataContext. Should it be a long-lived, application-scoped object or should it be a short-lived, request-scoped object? Let's get to the answer by considering the key parameters:

DataContext is ideally suited for a "unit of work" approach: Retrieve a bunch of objects through one or more queries, make changes to the resulting object graph based on user input (databound to controls) or some other request and then call SubmitChanges(). Where applicable, this can be a very efficient usage since all the changes in the unit of work are computed at once and the cost of query (or queries) is amortized over all the CUD operations. This is the case in case of a 2-tier app or in case of an SOA-type app where the service is sufficiently coarse-grained to allow this pattern.

DataContext is also designed for "stateless" server operation: In ASP.NET apps, it is important to minimize state. Plus the only scalable mechanism for maintaining "state" is to serialize it and DataContext is not (by design) serializable. Hence, we spent considerable effort in making DataContext lightweight to construct and disposable. For example, you can use pre-cooked mapping (MappingSource) and cache compiled queries and then use them with a request-scoped DataContext. Here, even the DataContext instances used for a query and a CUD (Create, Update, Delete) operation will be different. This is how it works in case of a web app using LinqDataSource.

With the two "patterns", let's look at some caveats if not antipatterns (YMMV)

Long-lived usage:DataContext does not itself overwrite the objects once you retrieve them through queries. So as time passes, the retrieved objects can become stale if they are frequently changed. Hence, the longer the elapsed time since the query (or queries), the greater the chances of running into an optimistic concurrency exception when you eventually call SubmitChanges(). Of course, how long is too long entirely depends on the characteristics of your data and application. This caveat not very relevant for reference data that is infrequently updated.

Life after SubmitChanges(): DataContext could be used after SubmitChanges() but one has to be careful. SubmitChanges() does all the hard work of figuring out all the changes you have made to the object graph. It orders the CUD operations for you and provides optimistic concurrency check at the granularity of each changed object. However, (by design), it does not do anything about the objects that you have only read but not changed. If those objects have changed in the database, then you have stale data that cannot be easily refreshed. Most applications are quite tolerant of not requiring checking of the "read-set" for submitting changes. However, as time passes, the staleness of "read-set" can be a problem.

In a nutshell,

  1. It is better to err on the side of shorter lifetime - a unit of work or even a single request for stateless servers are good patterns to start with.
  2. If you have reference data that doesn't get stale, then by all means consider using a long-lived DataContext instance. Again what is acceptable as "long life" will depend on your app.
  3. The dominant cost is likely to be queries rather than creation of a new DataContext instance. So use compiled queries and see if you can keep the reference data around. Don't sweat the overhead of creating DataContext instance for making a set of changes unless you have hard data from your app indicating that it is an issue. 
  4. If you want to use a DataContext instance for a long time or for more than one SubmitChanges(), take the time to understand the semantics (described above). It is not the best "default" usage.
  5. Above all, first think about the correctness or acceptable level of "staleness". Then, see if the DataContext lifetime is even on the critical path for perf. Otherwise, the cost of instantiating a DataContext is not terribly relevant (OK, that is a platitude but if I had a dollar for every attempt at premature optimization I saw, I would be a rich man! Yes, even though dollar buys a lot less these days, premature optimization seems to have become even more plentiful ;-) )

Dinesh

LINQ to SQL Tips 2: how to use common base class for all entities

Here is another question I get quite often: I have some common fields (maybe id and timestamp) and some common behavior across all my entities. How do I handle that in LINQ to SQL? After all, the only inheritance mapping supported is Table Per Hierarchy (TPH in ORM jargon). Here is a two part answer:

First, you shouldn't be using mapped inheritance in this case. It is unlikely that you have a single unique, enforced ID-space across all entities (i.e. across all mapped database tables). More likely, you want to encapsulate a pattern and common behavior. The right solution here is an abstract base class that is not mapped. The overridden properties can be mapped in each entity class. Here is a small example based on Northwind database. I have done hand-mapping to keep the example small but you can use SqlMetal to inject a common base class (caution: it is all entities or none, not on a per-entity basis and designer V1 does not support this). You still need to write the abstract base class manually and specify the override property for entity members in the designer. 

 

// Unmapped base class - written manually

abstract class EntityBase

{

    public virtual int ID { get; set; }

}

 

// Mapped derived classes - can be generated using designer/SqlMetal

[Table(Name = "Products")]

class Product: EntityBase

{

    int ProductID;

    [Column(Name = "ProductID", Storage = "ProductID")]

    public override int ID

    {

        get { return ProductID; }

        set { ProductID = value; }

    }

    [Column]

    public string ProductName;

}

 

[Table(Name = "Orders")]

class Order: EntityBase

{

    int OrderID;

    [Column(Name = "OrderID", Storage = "OrderID")]

    public override int ID

    {

        get { return OrderID; }

        set { OrderID = value; }

    }

    [Column]

    public string CustomerID;

}

 

// Strongly typed database connection

class Northwind : DataContext

{

    public Table<Order> Orders;

    public Table<Product> Products;

 

    public Northwind(string s) : base(s) { }

}

 

namespace BaseClassDemo

{   

 

    class Program

    { 

        static void Main(string[] args)

        {

            //NorthwindDataContext db = new NorthwindDataContext();

            Northwind db = new Northwind(@"Server=.\SQLExpress;Database=c:\Northwind\Northwnd.mdf;User Instance=True; Trusted_Connection=True");

            db.Log = Console.Out;

 

            var query1 = from o in db.Orders

                        where o.CustomerID == "AROUT"

                        select o;

 

            var query2 = from p in db.Products

                        where p.ID < 10

                        select p;

 

            // Write out the results of queries using ObjectDumper – available in VS2008 samples directory

            ObjectDumper.Write(query1);

            ObjectDumper.Write(query2);

 

        }

    }

}

The output is:

WHERE [t0].[CustomerID] = @p0

-- @p0: Input NVarChar (Size = 5; Prec = 0; Scale = 0) [AROUT]

-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.7

 

ID=10355        CustomerID=AROUT

ID=10383        CustomerID=AROUT

ID=10453        CustomerID=AROUT

ID=10558        CustomerID=AROUT

ID=10707        CustomerID=AROUT

ID=10741        CustomerID=AROUT

ID=10743        CustomerID=AROUT

ID=10768        CustomerID=AROUT

ID=10793        CustomerID=AROUT

ID=10864        CustomerID=AROUT

ID=10920        CustomerID=AROUT

ID=10953        CustomerID=AROUT

ID=11016        CustomerID=AROUT

ID=11081        CustomerID=AROUT

SELECT [t0].[ProductName], [t0].[ProductID] AS [ID]

FROM [Products] AS [t0]

WHERE [t0].[ProductID] < @p0

-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [10]

-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.7

 

ID=1    ProductName=Chai

ID=2    ProductName=Chang

ID=3    ProductName=Aniseed Syrup

ID=4    ProductName=Chef Anton's Cajun Seasoning

ID=5    ProductName=Chef Anton's Gumbo Mix

ID=6    ProductName=Grandma's Boysenberry Spread

ID=7    ProductName=Uncle Bob's Organic Dried Pears

ID=8    ProductName=Northwoods Cranberry Sauce

ID=9    ProductName=Mishi Kobe Niku

Press any key to continue . . .

 

 

LINQ to SQL Tips 1: how to map an enum

I was out on vacation (Zion, Bryce Canyon and Grand Canyon National Parks) so my blog went dark for a while. Also, I noticed a few comments that were incorrectly flagged by the spam filter - I have now published them, albeit after a delay. Sorry about that delay.

As we get closer to a release, it is time to mention a few less known LINQ to SQL (fka DLinq) features that I get emails about. Here is the first in the series about enum mapping. Here is an example based on the northwind database that enhances the usual generated Northwind DataContext and entity classes.

    public enum ShippingCompany {

        Undefined,

        FedEx,

        UPS,

        DHL

    }

 

    // A mini Order class with hand-mapping

    [Table(Name="Orders")]

    class EnumOrder

    {

        [Column(IsPrimaryKey=true)]

        public int OrderID;        

        [Column]

        public string CustomerID;

        [Column]

        public ShippingCompany ShipVia;

 

    }

 

    class OrdProj

    {

        public int OrderID;

        public string CustomerID;

        public int? ShipVia;

    }

 

    class NewNW: NorthwindDataContext

    {

        public NewNW(): base() {}

 

        public Table<EnumOrder> EnumOrders;

    }

 

    class Program

    { 

        static void Main(string[] args)

        {

            //NorthwindDataContext db = new NorthwindDataContext();

            //db.Log = Console.Out;

           

 

            NewNW db2 = new NewNW();

            db2.Log = Console.Out;

 

            var q = from o in db2.EnumOrders

                     where o.CustomerID == "ALFKI"

                     select o;

 

 

            var q2 = (from o in db2.Orders

                     where o.CustomerID == "ALFKI"

                     select new OrdProj { OrderID = o.OrderID, CustomerID = o.CustomerID, ShipVia = o.ShipVia }).Distinct();

 

            ObjectDumper.Write(q);

        }

    }

The output is:

SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[ShipVia]

FROM [Orders] AS [t0]

WHERE [t0].[CustomerID] = @p0

-- @p0: Input NVarChar (Size = 5; Prec = 0; Scale = 0) [ALFKI]

-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.7

 

OrderID=10643   CustomerID=ALFKI        ShipVia=FedEx

OrderID=10692   CustomerID=ALFKI        ShipVia=UPS

OrderID=10702   CustomerID=ALFKI        ShipVia=FedEx

OrderID=10835   CustomerID=ALFKI        ShipVia=DHL

OrderID=10952   CustomerID=ALFKI        ShipVia=FedEx

OrderID=11011   CustomerID=ALFKI        ShipVia=FedEx

Press any key to continue . . .

You can map an enum to integral type as in this case or to a string if the strings match the enum values (e.g. "FedEx").

 

Why doesn't everyone just speak English (or SQL)

There is already so much fictional/scientific/medical/... literature in English so why doesn't everyone in the world just speak English? There are so many dialects and variations of English that one has to often understand. Why bother with another language at all? After all, the purpose of inter-human communication is nicely served by English. What is with all those crazy people who speak other languages - especially when they are related to English (say Indo-European group of languages). 

Sorry, I misunderstood the question. You said what? Why are all query languages not just SQL? What is with this LINQ syntax anyway. Annonyingly like SQL but different? How dare you? What were you thinking? Why didn't you use T-SQL/PL-SQL/my-favorite-dialect-of-SQL?

Perhaps I (or others) could answer the question about specific features of LINQ syntax and why certain design choices were made for the minor matter of being consistent with the domain (objects) host programming language(C#/VB) and the environment (CLR, VS IDE). As for the more fundamental question, are you still looking for an answer? Really?

What do I know, I am not a native English speaker or a native SQL speaker for that matter :-). Although I use both the languages extensively and like them both a lot I don;t feel the kind of attachment that would lead to such questions.

Dinesh

DTOs or Business Objects

I keep getting a lot of questions about whether DLinq is for data objects or for business objects. There is no shortage of advice - both good and bad about what one should and should not do with DLinq.

Here, I want to briefly describe what we had in mind. It might not match someone's specific ideas about the terms "data objects" or "business objects" so hold your flame and send your feedback.

Here is how we approached the design:

  1. An entity maps to a single table or view and closely matches it in shape. Of course, you can project, change types, add non-persistent members, use inheritance but still, the entity is not a denormalized view of database entities. This helps us keep the updatability story simple. You don't have to be a rocket scientist or computer scientist for that matter to prove that the set of operations is fully contained within the ....
  2. For queries - LINQ provides punch through many traditional layers on mid-tier - your where clause on a collection can be sent to the server for execution directly. In this respect this is not like doing data access with a handful of sprocs (even though we try our best to support sproc-only access). If you don't need layers upon layers, don't add them. If your business entities are close enough to database tables/views, just add the logic in partial classes and minimize layers - avoid overengineering on speculation that some day, somewhere, somehow you might need the flexibility. When you actually need something, chances are that the overdesign really doesn't match the need.
  3.  If you are doing significant denormalization and/or aggregation in a business object, LINQ provides enough capability to shape your objects programmatically. Of course, the results may not be updatable but that is a hard problem that is best solved based on knowledge of the domain - not blindly through another programming language in the disguise of mapping.
  4. Entities are not loaded with database-specific methods (see this previous post).
  5. Entities are not loaded with persistence-infrastructure like original state. This keeps the objects fairly simple. You can start POCO and make an explicit decision to buy into change notification if you like. Plus, you don't have to worry about how to represent the state for transactional semantics when you have deleted the object. You don't have to worry about synching foreign keys with CLR references.
  6. Code generation is your friend and yet it is optional. You can write and map your own classes if you have are allergic to code generators. If you are not allergic and practical, we have done lots of things to make your life easy with options to change generated code. Partial classes, partial methods etc. offer plenty of customization points.Again, we are targeting the common case and may not have a solution for every single case.

These choices may not solve every object persistence problem and satisfy every taste. They were not meant to. We wanted something that made sense to a general .NET developer who is not steeped in ORM esoterica and expects something that is dependable and easily understandable. There were many times when we discarded flexible designs that had too many nuances and required too much expertise to clearly understand. We believe that the average .NET developer is trying to solve a business problem, not write another persistence framework on top. We wanted the existing intuition about CLR data model and CLR objects to be your friend and worked on minimizing additional concepts. As a result, there may not be lots of ways to do one thing. In some cases, there may not be any direct way to do exactly what you want to do. That, is "by design".

Some day, I hope to write more about the approach of C# design meeting (chaired by Anders Hejlsberg and attended regularly by colleagues like Matt Warren, Erik Meijer, Mads Torgersen and Cyrus Najmabadi). That is where LINQ and DLinq were cooked. But I must stop here - I have to run to catch a flight.

Dinesh

LINQ to SQL: What is NOT in RTM (V1)

Most of my posts have been about what is new in beta2 or RTM or how you can do great things with feature X and how bug Y has been fixed. Now that we are practically done with V1, it is time to do the somewhat unpleasant task of saying - sorry, this is not in V1. 

A lot of you have been very generous with your suggestions, feedback etc. In each case, we heard you, we (or at least I) am convinced of the merit of your suggestion. However, in the end, the limits of calendar and resources have played their part as have our own failings in what you might consider incorrect prioritization. This is necessarily a partial list based on frequency/strength of the feedback and consistency with what LINQ to SQL was designed for. I wanted to pick a small set of common ones.

  1. Support for other databases with or without a public provider model. Yes, we know that there are plenty of IT shops with more than SQL Server and for you ISVs and SIs, a broader bet is important.
  2. Out-of-the-box multi-tier story. Yes, we do have good Attach() APIs but we don't yet have a simple roundtripping and change tracking on the client. (I hope to work on some of these parts on my next project :-) )
  3. Handling schema changes. Schemas change and designer and SqlMetal should provide reasonable ways to respond to the changes.
  4. Support for specific mappings: containment (e.g. Address is a non-entity type and should be mappable differently for Customer.Address vs Employee.Address), pure many-to-many with no non-FK data in the middle table.
  5. Small differences between designer, SqlMetal and run-time: external mapping file and SSC support in designer
  6. LINQ to SQL in compact framework

Beyond V1, it is community's feedback that will help shape the direction. On that note, I am handing over the LINQ to SQL Program Management mantle to Tim Mallalieu in the SQL-DP team. I have moved to another project with the developer division at Microsoft (more about that on a sunny day).

If you think I missed something huge that should be in top 6 above, please post! 

Thanks,
Dinesh

No CRUD on entity please (aka anti-pattern of DB access methods on data/biz object)

I keep getting this question so often - "I want to do xyz. I have CRUD (Create, Read, Updated, Delete) methods on my entity class ...."

Stop right there. By now I have completely forgotten about "xyz" and I am rushing to climb on my soapbox!

While designing LINQ to SQL, we went to great lengths to avoid or at least minimize any coupling of an entity to data access operations (CRUD). This lets entities behave like data or business objects and makes them mobile from mid-tier to client. The whole point was to avoid having to dump the kitchen sink and its crud into the entity. Looks at wrapper methods for sprocs, override methods for CUD, Table<T> methods, SubmitChanges() or Attach(). All of them are _away_ from entities. This is not an accident! There are several reasons behind it:

  1. As mentioned above, this provides a better logical organization - the data and associated methods that manipulate the data in entity class and the persistence service in a separate class.
  2. Entities can be moved between tiers much more easily. Connecting to database from presentation tier is either unadvisable or simply not permissible. With the separation mentioned above, DataContext stays on the mid-tier while entities move around as needed. (We haven't done nearly enough in this area to make it even simpler but we have laid the foundation at least)
  3. (This is often negelected but important) The persistence operation is structured around a unit of work. If you modify multiple entities, you don't have to create another unit of work that calls the update methods on all the entities or even all entity classes. Just DataContext.SubmitChanges() is enough and it is done transactionally and with optimistic concurrency checks in that transaction.

To be blunt, if you are going to use LINQ to SQL, please don't fight the pattern it was designed for. The proverbial square peg of CRUD methods on entity is just not going to fit in the round hole of the DataContext as CRUD service provider design.

Now that this is out of the way, we can talk about the "I want to do xyz" part instead :-)

Dinesh

 

LINQ to SQL: features not in the designer / SqlMetal

I often answer questions based on what the run-time (System.Data.Linq.dll) supports, sometimes realizing only later that the run-time feature may not be supported by the visual designer in Visual Studio. Some of these are supported by the command line SDK tool SqlMetal.exe while others are supported by neither tool and require writing code (in C#/VB code editor in VS hopefully :-) )

Feature supported by designer but not by SqlMetal

  1. Many obvious things like selecting a subset of tables, columns, views, renaming members, changing types 
  2. Inheritance hierarchy mapping
  3. Unidirectional association (yes it is in the designer if you look at association properties just a bit longer)

Features supported by SqlMetal but not by the designer in VS (for most cases, see SqlMetal /? output)

  1. Extracting classes from SQL Server Compact (SSC)
  2. External mapping file
  3. Injecting a (unmapped) base class for all generated entities
  4. Sprocs returning multiple results
  5. Setting DeleteOnNull to true when it is inferred to false

Key features supported by neither design tool but supported by run-time (i.e you have to use code editor and write code the old fashioned way)

  1. POCO (Plain Old CLR Objects) - this is worth another blog post
  2. User overrides (e.g. sprocs) for relationship loading

I am sure I am forgetting some detailed ones in each category. OK, so please help me make the lists better!

Thanks,
Dinesh

LINQ to SQL breaking changes from beta2 to RTM (compiled from my LINQ forum posts)

Now that we are in the final weeks of locking down for RTM, it is worth tallying up the changes. Since betas are a bit experimental and intended for receiving feedback, the fact that there are changes shouldn't be surprising but we could do a better job of communicating the changes to our best customers - beta users and early adopters who help us polish the technology and take us to task for anything wacky (not just buggy). So here is a humble attempt to take a step in that direction

This post is just going to be a bunch of links to posts that have already covered this on LINQ forum.

LINQ to SQL Beta2 to RTM Key Changes

PLEASE READ: Beta2 to RTM Changes in Attach() Behavior

Beta2 to RTM change: XML column default mapping changed to XElement instead of XDocument

Beyond these salient ones, we are also working on a more detailed list to help you migrate smoothly from beta2 to RTM or to get your books, articles, blogs etc. in shape for .NET 3.5 / Visual Studio 2008 release. As I can scrape together some time, I am working on updating the LINQ to SQL paper that has not been updated since beta1 (so I won't even put URL for it until I do some badly needed updates)

10/10/07 Addition:

This is really a bug fix but worth mentioning in case the erroneous result went unnoticed in your code on beta2 and the exception on RTM build surprises you:

The intent was to not allow "partial entities" created through object initializer in projection. So the following query should have resulted in exception:

            var q2 = from c in nw.Customers

                     where c.City.StartsWith("M")

                     select new Customer

                     {

                         ContactName = c.ContactName,

                         City = c.City

                     };

Instead, in beta2, this query executed and gave n copies of the first object where n is the total number of rows produced by the generated SQL. This bug has now been fixed and the query will result in an exception. The main reason is that we don't want downstream confusion e.g. some path relying on Customer.Orders collection or an UPDATE statement created using uninitialized values. Of course, you can do the intended projection above with an anonymous or separate nominal type.

10/17/07 Addition

Mike Warriner pointed out another important one that I had missed: Beta2 dbml file needs to be opened and saved to get the right unicode encoding. On that note, as I have pointed out in the post, I would not use generated code from beta2 at all. I would suggest using the dbml file from beta2 project and regenerating code using designer (saving is enough to re-gen) or SqlMetal as appropriate. It is not a good idea to use the beta2 generated code with the RTM run-time.

Dinesh

Attach() if you have something detached

It is clear from the forums that this whole business of attaching detached objects in LINQ to SQL (DLinq) is confusing. Some of it is intrinsic, some is perhaps our design and perhaps a bit attributable to the misnomer "detached object support". More about the misnomer later but first here is the skinny on Attach() set of APIs. 

Think of a DataContext instance as a happy universe of objects where the entities (or objects with unique keys) are known to the DataContext instance since they were retrieved using that instance and the unknown ones are simply new entities that need to be inserted. Unfortunately, this simple picture is complicated by the fact that in a multi-tier system, entities may be sent over the wire in an ASP.NET app or web service client and then they may need to be brought back to the mid-tier for update. Add to that the fact that the mid-tier is often stateless so the DataContext instance used to retrieve the entity from the database may be long gone. A new DataContext instance can be spun up for update but the new one does not know about the deserialized entity that it did not retrieve. Attach() solves this problem by telling the new DataContext instance that the attached entity is meant to be updated and should not be inserted into the database.

Attach() needs to preserve the optimistic concurrency capability since that is how concurrent change conflicts can be detected and handled. So Attach() needs to deal with current and original values. This is what gives rise to the different flavors.

  1. Original values used for conflict detection: db.Customers.Attach(originalCust) should be used to attach the original values. The instance can then be modified (playback) before calling SubmitChanges().
  2. Original and current copies available: db.Customers.Attach(currentCust, originalCust) does it in one shot. Of course, this requires two instances with original and current values respectively.
  3. Timestamp or no optimistic concurrency members: db.Products.Attach(currentProd) In this case, original values are not required so current entity instance is enough. There is no playback needed before calling SubmitChanges().

When it comes to "detached object support", a question I often get is - what do I call to detach an entity? The answer is nothing! If an entity is serialized and deserialized back, it is already detached from the DataContext instance used for retrieval. If not, it may have deferred loaders that are tethered to the original DataContext. More significantly, Attach() is not intended to enable movement of entities across DataContext instances in the same app domain. This is not the intent (more about why that's the case some other day). In fact as I have mentioned on the LINQ forum, this is likely to cause an exception sooner or later so we have modified Attach() to throw if it is used on an object that is still attached to some DataContext instance. This change was done after beta2 and should be visible in RTM.

Detachedly yours,

Dinesh

Where was I hiding (aka lame excuse for not posting before)?

OK, now that I have fessed up to having a lame excuse, I will state it without further fear:

During much of September, my team-mates and I have been busy trolling forums and our inboxes for bug reports from customers in addition to copious ones that our QA team contributes. We wanted to get as many of them fixed as we could without doing radical changes that would impact the stability. Now that we are practically out of time for fixing any more bugs, I can turn my attention back to this blog.

But first a bit about the process itself:

We are constantly torn between users who chide us for not providing a "go live" license with our preview which our QA team hasn't even touched and users who admonish us for shipping products that have bugs. We can't satisfy the former due to our conscience (yes I do have one I think) and the latter due to practical impossibility. So we do what mere mortals have to - manage components to a schedule. The price of being on a train like Visual Studio 2008 is to satisfy the authorities like the station master and the conductor. You have to get a ticket, get on the train in time etc.

The last phase before the metaphorical train can leave the station involves something along the following lines:
Each component team has to make a "triage" decision about bugs that can and should be fixed vs. features that can be done in another release and bugs that can be postponed because they are either too minor to rise up in priority or too risky for the late stage. The decisions then get communicated to the product unit "ship room" and division's "ship room" as follows:
For a while, we are in "tell mode": we have to tell what we are doing and invite comments, scrutiny etc. This pushes component teams to think harder and ensures a consistent bar.
Then in "ask mode", it gets more interesting and we have to ask for permission to make any change for a bug fix at all. We present a case for fixing a bug, the actual fix, risk assessment, new tests etc. and then we may or may not get an approval depending on the jedi council's decision.

I can certainly imagine a beta user's frustration who reports a bug that is not fixed by RTM. However, the processes above ensure that the flow of changes is throttled and the product is stabilized so that it can be shipped on schedule.

Anyway, most of the bugs we could have fixed are behind us. Now I don't know if we can take any (and hope there aren't any so heinous that we will be allowed to take them). So I can do a bit more writing.

Apart from bug reports, we also found a constant stream of common questions and sources of confusion. Since I have a significant role in causing the confusion, I figured I will try to atone a bit with a few posts. Here are some thoughts from my side but feel free to contribute more. As usual, I will do the easy ones and leave the hard ones for you to figure out :-)

  1. Sprocs and LINQ
  2. Attaching detached objects (if only I can detach them first)
  3. Transacting in LINQ to SQL
  4. Joins vs. n queries for eager loading (why can't you do them joins)
  5. Top 3 bugs that we fixed
  6. What am I doing after Orcas (VS 2008, .NET Fx 3.5) ships
  7. Tintin in LINQ land

 Now I am digressing so better stop right here.

Dinesh

Orcas beta2: what's where (directories I mean)?

I got a few mails and saw a few forum posts about the confusion created by new locations for dll/exe in beta2. So here is where you can find LINQ to SQL related files.

  • New .NET Framework 3.5 DLLs (green bits) are in: Program Files\Reference Assemblies\Microsoft\Framework\v3.5\
  • SqlMetal.exe is in Program Files\Microsoft SDKs\Windows\V6.0A\Bin\

Another source of confusion - designer vs. SqlMetal

  • The visual designer for generating mapped LINQ to SQL classes is a part of Visual Studio 2008. You need to install some SKU of Visual Studio to use it.
  • SqlMetal.exe is a command line tool that is a part of the Windows SDK and lives in the same directory as similar command-line tools like Xsd.exe
LINQ to SQL (fka DLinq): What's new in Orcas beta2

Orcas beta2 is here for you. This is significantly ahead of beta1 and pretty close to the final feature set of Orcas for most components. The releases are available both as regular installs and as VPC images.  

Now that Orcas beta2 has been released, it is time to look at what's new there. But first, a general sense of how beta2 shaped up. Beta1 released in spring was mostly productization of the May 2006 LINQ CTP. So those who played with it only a little bit did not see a big change over May 2006 CTP - just API tweaks, more robustness etc.

Beta2 is a different animal. This is the first time we are able to do substantial additional features and reorg of features after wrapping up the core functionality for beta1. So here is what to look for:

  1. Significantly enriched code-gen: Looks for partial methods on DataContext and entity classes that can be extended in your partial class. Examples include
    1. Property setter validation methods (pre/post)
    2. Entity initialization and validation methods
    3. Create/Update/Delete (CUD) override methods (e.g. UpdateCustomer())
  2.  Unification of code gen. Now SqlMetal's code generator also powers the beautiful LINQ to SQL designer. So you can use either tool to gen your classes and get consistent results.
  3. LinqDataSource for your web apps that modify data but don't want to include a ton of custom code.
  4. Revamped and rationalized WinForms databinding support (no more ToBindingList() needed)
  5. Tonnes of perf improvements across the board. Rico has already blogged about this a lot. 
  6. Streamlined and enhanced support for detached objects (see Attach() APIs) for multi-tier apps
  7. SQL Server Compact (fka SQL CE) support in LINQ to SQL runtime and SqlMetal (though not in the designer)
  8. Better APIs for getting commands and changed objects (GetChangeSet/GetCommand instead of GetChangeText/GetQueryText)
  9. Inheritance enhancements - a relationship can be added in a derived class and a relationship to a derived class is now supported
  10. Partial trust support - now you can use it in ASP.NET medium trust with the addition of RestrictedMemberAccess permission
  11. Better serialization
  12. 500+ fewer bugs :-)
  13. Sweet sample - query visualizer is back by popular demand after disappearing in beta1 for a design overhaul.
  14. Lots of improvements in the designer for sproc handling - especially for insert/update/delete. But that is almost a separate topic best handled elsewhere
  15. A sweet mystery feature to give the power of dot to sprocs - more about it in a later post

Now I just have to update the online LINQ to SQL paper by crazily writing stuff over the next few days and provide the gist on my blog.


 

Saved by SSEUtil (you should have it too if you are a SQL Express user)

I did my TechEd talk about LINQ to SQL (DEV 348 if you want to do an easy search) last Friday. The start was very rough. I went to the designated room a good 20 minutes in advance only to discover that the room had been changed in the morning based on online schedules. Looks like the endless buzz about LINQ and plugs in various talks (Luca's, Scott Guthrie's) did the trick and the interest surged way past the capacity of the original room.

The helpful staff at the gate pointed me and a few other attendees to the correct room number in the wrong part of the center (South instead of the correct on in North). For those of you who haven't been to the Convention Center in Orlando, it is almost a mile away. Fortunately after walking a bit, I decided to check one of the screens that was showing the updates and found the error and got to the right room just two minutes before (after informing the helpful but mistaken staff members). The room was large but quite hot - some issue with the AC I presume).

With no time to start afresh, I skipped the usual steps of rebooting and trying out the first step. That cost me dearly! Ten minutes into the talk and I got my first exception with SQL Server Express since the file was already attached. Not good! Without a DB to connect to, it would have been game over. Fortunately, Antoine's nifty utility SSEUtil.exe came to the rescue. A quick change to a command prompt and two executions is all it took

sseutil -m -l
sseutil -m -d C  (the mdf file path started with C:\)

Most in the audience saw it as a relatively minor glitch and probably forgave me for it. I did lose a few precious minutes that resulted in the loss of databinding demo in VB that I had meticulously planned.

Apparently, the audience liked the talk and rewarded me with pretty good scores and some in-person compliments afterwards. But that is besides the point. The main point here is that if you play around with SQL Server 2005 Express Edition, keep SSEUtil handy.

Thanks Antoine!

I hope to do a few more posts soon about LINQ to SQL questions at TechEd and TechMela and their answers. Stay tuned.

Search

This Blog

Syndication

Page view tracker