LINQ to SQL : FAQ Answer By Matt Warren

Wonderful composition of FAQ is available at by Matt Warren.

Q: How do I get default values from the database when inserting new entities?

A: LINQ to SQL does not support using default values from the database. The values in the entity at the time SubmitChanges is called are used instead. You can override how LINQ to SQL inserts entities by implementing an insert method on the DataContext. For an entity type called ‘Entity’ implement a function with the signature of ‘InsertEntity(Entity instance)’.

Q: How do I attach and update entities? When I attach and call SubmitChanges nothing happens.

A: Attaching entities to a DataContext may not work as you intend. An attached entity is merely the equivalent of an entity that has just been queried from the database and not yet modified. In order to instruct the DataContext that you intend to have the entity updated you must provide it with information describing how the entity has changed. You can do this in a variety of ways. 1) You can call Attach to add the entity to the DataContext and then modify individual properties. This assumes the entity is not already in a modified state. 2) You can call the form of Attach that takes both a current and original instance of the entity. The DataContext will recognize that individual properties values differ. 3) You can call the form of Attach that takes an additional Boolean parameter set to true to indicate that the DataContext should treat the entity as all properties modified. The option requires that the object have a version property.

 Q: How do I serialize entities using .Net Remoting?

A: LINQ to SQL does not support serialization using .Net Remoting. Key data types such as EntityRef and EntitySet are not serializable.

Q: How do I serialize entities using WCF (Windows Communication Foundation)?

A: LINQ to SQL supports serialization as XML via WCF by generating WCF serialization attributes and special serialization specific logic during code-generation. You can turn on this feature in the designer by setting serialization mode to ‘Unidirectional’. Note this is not a general solution for serialization as unidirectional mode may be insufficient for many use cases.

Q: How do I move entities between tiers in my multi-tier application?

A: While it is possible to use WCF serialization to move entities between tiers it may be insufficient for your application as it will not allow for round-tripping of changes. Defining a custom data exchange contract as part of your web service API is a better all around solution.

 Q: Should I create a new DataContext in every business logic method?

A: The DataContext conforms to the Unit of Work design pattern. Unless you are moving data between physical tiers between each operation you should keep your DataContext alive for the duration of work.

Q: Should I keep my DataContext in a static/global/shared variable?

A: The DataContext is not thread safe and is not meant to be shared. A DataContext is meant to be used for a single unit or work or at most for multiple consecutive units of work.

Q: Where should I put my business logic? The system I’m currently developing uses static methods on the entities themselves for loading, saving and other operations.

A: The DataContext conforms to the Unit of Work design pattern. A work context must exist and be maintained separate from the entities themselves. You should either place all your business logic as methods on the DataContext or devise a separate business context that encapsulates a DataContext instance. You should not be using static methods.

Q: Are LINQ to SQL entities Business Entities or Data Transfer Objects? How do I build a business layer on top of LINQ to SQL?

A: LINQ to SQL entities are both business entities and data transfer objects. LINQ to SQL takes the place of your Data Access Layer and is the basis for your Business Layer. You can add business logic directly to the DataContext or encapsulate the DataContext in your own business context. The purpose for making a separate business context would be to restrict access to other DataContext methods. If this is not an issue for you, putting all business logic methods on the DataContext is the best choice.

 Q: How can I keep entities cached beyond the lifetime of a single DataContext? I want to keep a collection of entities in a cache so that all subsequent requests can read from this cache instead of going back to the database each time.

A: It is possible to cache entities beyond the lifetime of a single DataContext. However, it is dangerous to do this for entities with defer loaded properties as you are likely to get accesses back to the originating DataContext if these properties are ever navigated. You are also likely to unintentionally retain all entities materialized via that same DataContext causing what may appear to be a memory leak. To alleviate these problems you can either turn deferred loading off when first retrieving these entities or you can dispose the DataContext after the entities are fully loaded using an operation such as ToList or ToArray.

 Q: How can I re-attach an entity to a new DataContext? When I try to do this I get an exception thrown.

A: LINQ to SQL does not support re-attaching entities. Entities are never actually detached from their originating DataContexts. The Attach methods are intended to be used with entity instances that are newly created after round-tripping data from another physical tier. LINQ to SQL detects that an entity belongs to another DataContext if any deferred properties are still unloaded. It is possible to trick the DataContext into accepting entities from another DataContext by either not having deferred properties, pre-loading all of them or turning deferred loading off on the originating DataContext.

 Q: How can I use globally cached entities to initialize the association properties of a new entity instance or to change an association property in order make an update? When I try this I get strange behaviors like inserts I did not intend or exceptions thrown during SubmitChanges.

A: LINQ to SQL does not support mixing and matching entities loaded from different DataContext instances together in the same object graph. Trying to do so is generally a bad idea. Most association properties are bi-directional, so assigning one to a property of another or adding one to a collection property changes state and references in both entities. This means that globally cached entities are being modified potentially on multiple threads at the same time (when running as a service). As a general rule of thumb, a single connected entity graph should only be associated to a single unit of work at a time. Instead of using globally cached entities to assign association properties, use entities retrieved from the DataContext you are using to perform the insert or update, or assign values to the foreign key fields directly to avoid extra round-trips to the database server.