Thoughts from Dan Miser RSS 2.0
# Friday, 22 July 2011
The conversion is finally on. I've had a lot of praise for LightSpeed over the years. The guys writing it are wicked smart, and Ivan is a rockstar on the support forums. They've solved a lot of bugs for me while I've been a customer, but the time has come to move on.

I've become quite proficient with LINQ, and use it all over the place in my code. Having to drop down and execute loops and run suboptimal queries because I have to execute an intermediate ToList() just to get around projection and grouping errors has taken its toll on me.

I truly wish the guys at Mindscape continued success, but the time has come to move on to the company that provides a MSSQL LINQ provider that is completely fleshed out.

Friday, 22 July 2011 01:39:06 (GMT Daylight Time, UTC+01:00)  #    Comments [0] -
# Friday, 15 October 2010
Given a method like this, with the following LINQ to SQL statement in it:

public void DisplayReport(UserStatusEnum? userStatus)
from user in DBContext.Users
where userStatus == null ? true : userStatus.Value == user.Status
select user

I end up with the error "Nullable object must have a value". Matt Warren (one of the original developers on the LINQ to SQL team, and a wicked smart guy), came up with the idea to use target="_blank">object.Equals(userStatus, user.Status), but that doesn't work for me at all in the case where userStatus is NULL. What worked for me was to do this:

from user in DBContext.Users
where userStatus == null || userStatus == user.Status
select user

The thing is, as one commenter in the linked thread mentioned, LINQ to SQL should be a unifying syntax. We shouldn't have to distinguish between NULL and values just because the underlying provider makes a distinction between the two. I think this is a huge hole, but alas, one that will most likely never be plugged since LINQ to SQL is getting deprecated. Time to check what happens in EF4...

Friday, 15 October 2010 18:41:07 (GMT Daylight Time, UTC+01:00)  #    Comments [0] -
# Tuesday, 05 January 2010
Consider this code fragment:
var list =
from tx in Transactions
group tx by new {tx.TransactionType, tx.ClientTypeID};

foreach (var item in list)
Console.WriteLine(item.Sum(tx => tx.Amount));
foreach (var item2 in item)

After executing the query, we now have an IGrouping<AnonymousType, Transaction> that lets us run through all of the grouped objects, while still having access to the original objects in the inner loop. We can accomplish the exact same thing with this alternative LINQ statement, but the first version seems cleaner to me:

var list =
from tx in Transactions
group tx by new {tx.TransactionType, tx.ClientTypeID} into g
select g;
Tuesday, 05 January 2010 16:30:01 (GMT Standard Time, UTC+00:00)  #    Comments [0] -
# Friday, 16 October 2009
Given a collection of players that were constructed like this:

private static IList<Player> LoadPlayers()
	Player favre = new Player { Id = 1, Name = "Favre", Team = new Team { Id = 1, Name = "Vikings" } };
	Player peterson = new Player { Id = 2, Name = "Peterson", Team = new Team { Id = 1, Name = "Vikings" } };
	Player rodgers = new Player { Id = 3, Name = "Rodgers", Team = new Team { Id = 2, Name = "Packers" } };
	Player driver = new Player { Id = 4, Name = "Driver", Team = new Team { Id = 2, Name = "Packers" } };

	List<Player> players = new List<Player> {favre, peterson, rodgers, driver};
	return players;

And the following LINQ query:

var query = 
	from p in LoadPlayers()
	group p by p.Team into g
	select g;

We will see the following output:


The reason this is happening is that we created new Team objects for each and every Player, and when LINQ tries to group, it does so based on object equality. The solution to this is to override the Equals() and GetHashCode() methods in the Team class. After doing that, the LINQ query will be able to group the objects up properly and just display each team name once. Resharper has a nice code generation template to create solid implementations of these methods (press Alt+Ins to bring up the code generation menu).

The example here is obviously contrived. We could create each team object once, and then use the same instance during the property assignment, and if we did that, things would work just fine. However, I ran into a more generalized version of this problem when using WCF and a lot of custom code generation. The underlying lesson is still the same: LINQ and GroupBy need to have object equality defined properly in order to make things work as you would expect.

Friday, 16 October 2009 19:14:18 (GMT Daylight Time, UTC+01:00)  #    Comments [2] -
# Friday, 11 January 2008

To be sure, this is an incomplete list, but it is a good start. Here's what I don't like about LINQ to SQL:

  • It only works with MSSQL. Yes, this point has been beaten to death, but it is entirely justified. Third party solutions don't cut it. LINQ to SQL intentionally seeks to exclude a sizeable population because of this hair-brained decision.
  • No way to easily specify adhoc LINQ queries. This doesn't count. I know the benefits of design-time queries, but I should also be allowed to shoot myself to get the added flexibility if I so choose. Building up expression trees is not a viable option for every day development.
  • The constant labeling of LINQ to SQL as an OR/M. That label considerably overstates what this technology does. One to one mapping between a table and a class is not really OR/M. It seems like they want to force you to change your database by writing stored procs and views to make your object model better.
  • There is no automated way to easily pick up changes to the database schema.
  • There is no easy way to preserve changes to the generated code. e.g. I change the name of the automatically generated class from collection_details to CollectionDetails, but I evolve the schema of the table. When I re-add the table, I need to set all of the custom properties again. I know I shouldn't change generated code, but see the next point.
  • Speaking of collection_details, it would be much better if the underlying class generator had some options to clean up legacy table names (e.g. remove underscores, camel case resulting table and column names).
  • No many-to-many support. In short, when you have an junction table (aka associative table or cross-reference table), you will need to write code like this: User.UserPermissions[0].Permission vs. User.Permissions[0]. Until we see LINQ to Entity (if ever), we do have this, but you can't use the new entity in a LINQ query.
  • There is no built-in solution to using LINQ across tiers. I don't want to expose my LINQ classes (see the point above about the tight coupling between database and objects) as I may want to change my database, and I don't want that cascading to all of the places that use it. There is also no diffgram, so even if I did it, I would have to write my own change tracking and resolving support. I went to an OpenSpaces meeting on this very topic during CodeMash, and the consensus was not flattering.

In short, it seems like this part of LINQ was released way before it was ready. But it does demo well...

Feel free to add your own grievance to the comments.

Friday, 11 January 2008 18:23:26 (GMT Standard Time, UTC+00:00)  #    Comments [5] -
# Sunday, 30 December 2007

I have been reading Dustin Campbell's series, The 12 Days of Refactor! X-mas, with interest. He's a very good writer, and has broken down a bunch of Developer Express features into easy to digest chunks of information.

The episode I linked to above touched on the XML Literal support that shipped with VB in Visual Studio 2008. The one sentence summary of this technology is that it lets the VB compiler translate raw XML in the source code into strongly-typed code using XML classes under the hood. It's a very nice idea, and I encourage you to look at the links to learn a little more about it.

While the VB team thought this was a good idea and added the feature, Anders and the C# team believed that it was superfluous to add such a thing to the C# side. I haven't really made up my mind which group I side with yet. However, Anders is benevolent :-), so he gave us the little-documented PasteXmlAsLinq addin that will take XML on the clipboard and paste it into a file in C# syntax building the XML up using classes like XElement.

In a default install of VS2008, open C:\Program Files\Microsoft Visual Studio 9.0\Samples\1033\ and extract the LinqSamples\PasteXmlAsLinq files. There is a Readme.html file in there that tells you how to build, install and use the addin.

While this isn't the same as VB's support for XML Literals, it does make things easier to work with.

Sunday, 30 December 2007 23:02:25 (GMT Standard Time, UTC+00:00)  #    Comments [1] -
# Thursday, 08 February 2007
I was banging through some quick and dirty sample applications today, in preparation for a talk on LINQ tonight. One of my old LINQ to SQL demos shows how to use the external xml mapping file. I also blogged about this before. Today, I kept getting the following error whenever I would run with an external xml mapping file:
The type 'Order' is not an entity.

I was using the following command line to generate the xml mapping file:

SqlMetal /server:(local) /database:Northwind /map:Northwind.xml /code:Northwind.cs /pluralize

Looking at the resulting xml file, I finally noticed this section:

  <Table Name="Orders">
    <Type Name=".Order">

Notice the leading dot before the type name attribute. That's the problem. So I went back and added the /namespace switch to the sqlMetal command line, and now all is well with the world again. Granted, this problem is the result of me doing demo work, and not production work, but it's still a little bit irritating. Then again, I'm still running the May 2006 CTP on VS2005, so for all I know, MS has already fixed all of this with a subsequent release of a build in Orcas.

Thursday, 08 February 2007 19:23:16 (GMT Standard Time, UTC+00:00)  #    Comments [0] -
# Friday, 23 June 2006
The following code snippet shows how to pick up the SQL that will be generated by a given LINQ query. The DataContext.GetQueryText() method makes this very easy. However, what we REALLY need is an easy way to go the other way, too. For example, given an adhoc string, generate the DLINQ query to allow further processing. I've looked through the Interactive Query sample, but that's not exactly what I want. The 2 main things wrong with it are that the baseQuery is already defined as an IQueryable variable, as opposed to a simple string; and the code to build up the expression tree is much too complex for every day needs. If we had a generic string to IQueryable method, we wouldn't need all of the expression code.

        static void Main(string[] args)
            string s;
            var q  = from e in db.Employees select e.FirstName;
            s = db.GetQueryText(q);

Friday, 23 June 2006 18:08:00 (GMT Daylight Time, UTC+01:00)  #    Comments [5] -
# Friday, 26 May 2006
Using LINQ, you can use variables for evaluation of the query. For example, the following query works just fine. It would also work if you used something like textBox1.Text instead of the variable s.

    string s = "Beverages";
    var results = from c in db.Categories
                  where c.CategoryName == s
                  select c.CategoryName;
Friday, 26 May 2006 14:18:00 (GMT Daylight Time, UTC+01:00)  #    Comments [0] -
# Tuesday, 16 May 2006
In the README for the LINQ download, one big feature that was mentioned was the ability to use an external XML mapping file instead of attributes. This decouples the schema information from the code, which is good as a database schema tends to change over time, and you don't want to recompile every time your DBA decides to change something on you. The down side is that there isn't much information out there on how to get it to work. Hopefully, this entry fills that gap.

The first thing to note is the syntax of the XML mapping file. You can take a look at LINQ Preview\Docs\DLINQ Mapping Schema.xsd for more information on the mapping format, but here is a shortened extract from LINQ Preview\Data\samplemapping.xml to give you a look at a concrete implementation:

<?xml version="1.0" encoding="Windows-1252"?>
<Database Name="Northwind">
  <Table Name="Categories">
    <Type Name="Mapping.Category">
      <Column Name="CategoryID" Member="CategoryID" Storage="_CategoryID" DbType="Int NOT NULL IDENTITY" IsIdentity="True" IsAutoGen="True" />
      <Column Name="CategoryName" Member="CategoryName" Storage="_CategoryName" DbType="NVarChar(15) NOT NULL" />
      <Column Name="Description" Member="Description" Storage="_Description" DbType="NText" UpdateCheck="Never" />
      <Column Name="Picture" Member="Picture" Storage="_Picture" DbType="Image" UpdateCheck="Never" />
      <Association Name="FK_Products_Categories" Member="Products" Storage="_Products" ThisKey="CategoryID" OtherTable="Products" OtherKey="CategoryID" />

The above code shows how the Categories table in the Northwind database could be mapped in an XML file. One thing of special note here is the Association element which will allow data hierarchies to be established, much like you can do in the DLINQ designer. You can generate this file by hand if you want, or you can use the new version of LINQ Preview\bin\sqlMetal.exe to generate the starting point for you. sqlMetal has a lot of options for you to look at, including a bunch to take save snapshots of database schema information to an xml file, and generate classes and XML mapping files from that saved XML file. A sample command would look like this:

sqlmetal /server:(local) /database:Northwind /map:nwindmapping.xml /namespace:Mapping /code:nwind.cs

The resulting nwind.cs file does not contain any attributes, as they are all stored in the xml file. To use this file, use code like this:

    XmlMappingSource mappingSource = XmlMappingSource.FromXml(File.ReadAllText("nwindmapping.xml"));
    Mapping.Northwind db = new Mapping.Northwind("Integrated Security=SSPI;database=northwind;server=(local)", mappingSource);
    var q = from c in db.Categories 
            select c.CategoryName;
    foreach (string s in q)
Tuesday, 16 May 2006 19:10:00 (GMT Daylight Time, UTC+01:00)  #    Comments [2] -
# Thursday, 11 May 2006
LINQ is coming along nicely. This release is full of goodies. Among my favorites: join support, DLINQ graphical designer, LINQ over DataSet, multi-tier enhancements, and improved conflict resolution. But the thing I'm most excited about is the addition of XML mapping of elements! I attended a talk on ORM by Sean McCormack at the WI .NET User Group last night. He is an excellent speaker and spoke about DLINQ for a couple minutes, but hated the fact that it didn't have XML mapping. Maybe this will bring him around. :-) It also looks like I'll be speaking at the WI .NET User Group on LINQ in the medium-term future. I'll be sure to post more about that event and more findings with LINQ. In the meantime, download the CTP now.
Thursday, 11 May 2006 01:51:00 (GMT Daylight Time, UTC+01:00)  #    Comments [0] -
# Saturday, 29 October 2005
A version of LINQ that is compatible with the RTM version of VS2005 has been released on this page.
Saturday, 29 October 2005 16:00:00 (GMT Daylight Time, UTC+01:00)  #    Comments [0] -
# Friday, 23 September 2005
As I mentioned in my previous post about LINQ and IDENTITY fields, I was getting an exception when trying to update back to the DB. I have since tracked this down to my guess in that post where it was due to the way that I constructed the customer object via foreach. Using that technique, it seems that it keeps a DataReader open longer than needed, which results in this error. I have a workaround, so I can at least share this sample to show you how related tables with IDENTITY fields work. If you want to see the exception, replace the line where I assign the cust variable with a "foreach (var cust in query)".

Things to note in this sample:

  • I am mixing and matching objects retrieved from the DB (cust) and locally created objects (o and od).
  • You can assign the Order object to the customer either by setting o.Customer to point to the customer, or using cust.Orders.Add(o). The same holds true for adding OrderDetail to Order.
  • IDENTITY fields are not initialized upon creation, but they are assigned the actual value that they got when getting inserted to the DB.
  • You can link tables together by either using the object references or the actual data field. For example, when building the OrderDetail object, I use od.ProductID to set the value that will get written to the DB. I could also have constructed/received a Product object from the DB and assigned od.Product to do the linking via object reference.
  • Linking between related tables is taken care of automatically, even when linked via IDENTITY fields

    class Program
        static void Main(string[] args)
            Northwind db = new Northwind(
                @"Data Source=(local);Initial Catalog=Northwind;Integrated Security=True");
            db.Log = Console.Out;

            var query = from c in db.Customers
                        where c.CustomerID == "ALFKI"
                        select c;

            Customer cust = query.ToArray()[0];
            Order o = new Order();
            o.Customer = cust;
            o.Freight = 23;
            Console.WriteLine("[PRE] Order.OrderID == " + o.OrderID);

            OrderDetail od = new OrderDetail();
            od.Order = o;
            od.Quantity = 1;
            od.ProductID = 1;
            Console.WriteLine("[PRE] OrderDetail.OrderID == " + od.OrderID);


            Console.WriteLine("[POST] Order.OrderID == " + o.OrderID);
            Console.WriteLine("[POST] OrderDetail.OrderID == " + od.OrderID);
Friday, 23 September 2005 19:54:00 (GMT Daylight Time, UTC+01:00)  #    Comments [0] -
# Monday, 19 September 2005
In the current version of DLINQ, you can only target MSSQL. The architecure seems to be extensible enough to allow for DBMS vendors to provide their own DLINQ assemblies so that when you write DLINQ queries, you will be allowed to communicate to a variety of back-ends. See System.Data.DLinq.Provider.ProviderContext for the class that you can use to descend from in order to get your own DBMS supported. Talking with MS, it appears that they are hoping that each and every vendor will provide their own assemblies. I think this is a mistake for the following reasons:

  • First off, the current code in System.Data.DLinq.DataContext uses code in System.Data.DLinq.SqlClient. It essentially forces the ProviderContext to be SqlClient. This will have to be cleaned up and made more generic before a vendor can deliver something.
  • I believe it's time for MS to start providing tools that allow the developer to mix and match parts. Until MS does this, they will continue to develop solutions that work well with MSSQL, but will miss out on what other DBMSes can do. They need to take the lead by providing other DBMS versions so they can see where the holes in their current approach are. If they wait for the vendors, it will most likely be too late to change the code to do what needs to be done to support 3rd party DBs. It's a Catch-22. DB vendors will wait to write their assemblies until MS cleans up the code (see point 1 above), and see that doing this will yield positive returns. When they finally do this, it may be too late to have the DLINQ architecture changed to accomodate whatever specific hooks may be required to get first-class support of the 3rd party DB.
  • It doesn't appear that there is any registration/management code in place to allow for you to simply say: "I'd like to use MSSQL (or Oracle, or InterBase)". It seems that this would be resolved by which assemblies you reference in your code. But how well will this work when you want to target multiple DBs in your application?
  • Finally, the competition (i.e. Borland) already provides low-level multi-DB code in several cases, and has for years: BDE, DBExpress, and Borland Data Providers (BDP). If a company with a development team that is a minute fraction of MS's development team can deliver this, there's no reason MS couldn't do the same.
Monday, 19 September 2005 04:14:00 (GMT Daylight Time, UTC+01:00)  #    Comments [5] -
# Saturday, 17 September 2005
There is some conflicting information out there about what you need to run LINQ. This link says that the C# LINQ Tech Preview will only work with VS.NET 2005 Release Candidate (RC). What is troubling is when you download the MSI file from that page, it is the same exact MSI file as the one distributed on Disc 4 at PDC. That file would only install on VS.NET 2005 Beta 2.

To make matters worse, this link tells us that the VB LINQ Tech Preview from the web site will only work with VS.NET 2005 RC (as does The LINQ Project Page). If you install RC and then the VB LINQ Tech Preview, you'll find that the files that get installed are newer than the C# version. However, the VB package is missing the System.Data.DLinq assembly.

I imagine updates will be coming to sort all of this out soon, but just thought you should be aware of the current state of things. To make things simple for now, use Beta 2 and C#.

Edited on 9/17 to add: Looks like MS updated the page to say that C# only works with Beta 2.

Saturday, 17 September 2005 05:13:00 (GMT Daylight Time, UTC+01:00)  #    Comments [1] -
.NET Language Integrated Query (LINQ) is here. We've seen a couple of teasers over the past few months, but after seeing this stuff in-depth for a few days, I have to admit that I love what I see. So much so, that I created a new feed for it because I plan on writing about LINQ quite a bit. For now, the generic description will have to do. It's a way to write query-like statements that can operate on sets, XML, data, and more using one syntax. Furthermore, this is all available in your native programming language (C#, VB, and others will follow soon, I'm sure), which means rich type information at design-time, and it's strongly-typed so you'll see errors at compile time. It's in beta right now, and there are all sorts of known warts, but the promise of a useful and valuable tool is excellent.

Stay tuned for more information on LINQ!

Saturday, 17 September 2005 02:05:00 (GMT Daylight Time, UTC+01:00)  #    Comments [0] -
<2018 May>
About the author/Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2018
Dan Miser
Sign In
Total Posts: 388
This Year: 0
This Month: 0
This Week: 0
Comments: 630
Pick a theme:
All Content © 2018, Dan Miser
DasBlog theme 'Business' created by Christoph De Baene (delarou)