
Skill
migrating-linq-to-sql-to-ef-core
migrate LINQ to SQL to EF Core
Description
Migrates LINQ to SQL (System.Data.Linq) data access layer to Entity Framework Core during .NET Framework to modern .NET upgrades. Covers DataContext to DbContext conversion, DBML entity mapping to EF Core model configuration, stored procedure migration, query translation differences, and concurrency handling changes. Use when assessment detects LINQ to SQL usage or when upgrading projects referencing System.Data.Linq. Triggers for "LINQ to SQL", "System.Data.Linq", "DataContext migration", "DBML to EF Core", "linq2sql", "migrate LINQ to SQL".
SKILL.md
LINQ to SQL to Entity Framework Core Migration
Overview
Migrates .NET Framework projects from LINQ to SQL (System.Data.Linq) to Entity Framework Core. LINQ to SQL is not available in .NET 6+ — this is a migration blocker, not an optional improvement.
Reference files for detailed patterns:
ref/entity-mapping-conversion.md— DBML/attribute mapping to EF Coreref/datacontext-to-dbcontext.md— DataContext lifecycle and API migrationref/query-translation-gotchas.md— Query behavior differences (critical for runtime correctness)ref/stored-procedure-migration.md— SP/function mappingref/concurrency-and-change-tracking.md— UpdateCheck/conflict resolutionref/relationship-migration.md— EntitySet/EntityRef to navigation properties
Prerequisites
Verify LINQ to SQL usage before proceeding:
- Check for
System.Data.Linqassembly reference in the project file - Search for
.dbmlfiles in the project directory - Search for
using System.Data.Linqin code files
If none found, skip this skill.
Workflow
Migration Progress:
- [ ] Step 1: Assess LINQ to SQL usage scope
- [ ] Step 2: Set up EF Core infrastructure
- [ ] Step 3: Scaffold or convert entity model
- [ ] Step 4: Migrate DataContext to DbContext
- [ ] Step 5: Migrate stored procedures and functions
- [ ] Step 6: Fix relationship loading patterns
- [ ] Step 7: Migrate concurrency handling
- [ ] Step 8: Fix query translation issues
- [ ] Step 9: Validate
- [ ] Step 10: Remove LINQ to SQL artifacts
Step 1: Assess LINQ to SQL Usage Scope
Before making changes, inventory the full scope. This determines effort and identifies blockers.
Find and count:
.dbmlfiles and their entity/SP counts (parse the XML)- DataContext classes (search for
: DataContextor: System.Data.Linq.DataContext) - DataContext instantiation points (
new *DataContext() - Stored procedure mappings (
[Function(attribute usage) IMultipleResultsusage (blocker — no EF Core equivalent; seeref/stored-procedure-migration.md)EntitySet<T>andEntityRef<T>usage countsUpdateCheck.WhenChangedusage (requires concurrency strategy decision)- Partial class extensions of generated entities (business logic to preserve)
Flag these blockers early:
IMultipleResults→ requires ADO.NET fallback or SP redesignUpdateCheck.WhenChanged→ no direct EF Core equivalent (seeref/concurrency-and-change-tracking.md)
Step 2: Set Up EF Core Infrastructure
- Add NuGet packages:
Microsoft.EntityFrameworkCore.SqlServer(or appropriate provider)Microsoft.EntityFrameworkCore.Design(for tooling)
- Ensure the project targets .NET 6+ (should already be the case in an upgrade scenario)
Step 3: Create New EF Core Entity Model
CRITICAL: Create new files — do NOT rewrite the DBML-generated *.designer.cs file in place.
The *.designer.cs file (e.g., CompanyDB.designer.cs) was auto-generated by the LINQ to SQL O/R Designer. It is full of LINQ to SQL plumbing (INotifyPropertyChanging, EntitySet<T>, EntityRef<T>, OnXChanging/OnXChanged partial methods). Do not attempt to "convert" this file into EF Core entities — it will retain confusing artifacts and the .designer.cs name implies auto-generation.
Instead, create new clean files:
- New DbContext file — e.g.,
MyDbContext.cs(or{OriginalDataContextName}DbContext.cs). Define theDbContextsubclass withDbSet<T>properties here. - New entity class files — create one file per entity class (e.g.,
Entities/Customer.cs,Entities/Order.cs) or a singleEntities.csfile for small models. Write clean POCO classes with EF Core data annotations or Fluent API configuration. - Preserve partial class logic — if the project has partial classes extending DBML-generated entities (separate from the
.designer.csfile), migrate that business logic into the new entity files.
Recommended approach: Scaffold first, then reconcile.
- Use
dotnet ef dbcontext scaffold "ConnectionString" Microsoft.EntityFrameworkCore.SqlServer -o Entitiesto generate baseline entities from the existing database into a new folder - Compare scaffolded entities with DBML-defined entities:
- Reconcile custom C# names from DBML (the DBML may rename entities/properties differently from the database)
- Preserve custom partial class logic from existing code
- Apply Fluent API configuration for non-convention mappings
- If scaffolding is not possible (no database access), manually create entity POCOs by reading the
.dbmlXML to extract table/column definitions, then translate to EF Core attributes
See ref/entity-mapping-conversion.md for the complete attribute mapping table and DBML conversion strategy.
Important: During conversion, both LINQ to SQL and EF Core use [Table] and [Column] attributes from different namespaces. Use fully-qualified names or manage using directives carefully to avoid ambiguous reference errors.
Step 4: Migrate DataContext to DbContext
Replace all DataContext usage with the new DbContext class created in Step 3. This is not just a rename — the lifecycle model differs fundamentally.
Update all consuming code to reference the new DbContext class name and the new entity types:
Table<T>properties →DbSet<T>propertiesSubmitChanges()→SaveChanges()/SaveChangesAsync()GetChangeSet()→ChangeTracker.Entries()ExecuteCommand()→Database.ExecuteSqlRaw()ExecuteQuery<T>()→FromSqlRaw()/SqlQueryRaw<T>()DataContext.Log→ILoggerFactory/LogTo()onDbContextOptionsBuilderObjectTrackingEnabled = false→AsNoTracking()queries- Direct instantiation (
new MyDataContext(conn)) → DI-injected DbContext
Critical: If DataContext was used in using blocks and you migrate to DI-managed DbContext (scoped lifetime), remove the using blocks — the DI container manages disposal. Keeping both causes premature disposal.
See ref/datacontext-to-dbcontext.md for detailed API mappings and lifecycle patterns.
Step 5: Migrate Stored Procedures and Functions
LINQ to SQL maps SPs as methods on DataContext with [Function] attributes. EF Core has no attribute-based SP mapping.
For each stored procedure:
- SPs returning entity types →
FromSqlRaw("EXEC sp_name @p0, @p1", params) - SPs with no return →
Database.ExecuteSqlRaw() - SPs with non-entity results →
SqlQueryRaw<T>()(EF Core 8+) with[Keyless]result types - SPs with output parameters → use
SqlParameterobjects directly - UDFs →
HasDbFunction()in Fluent API
See ref/stored-procedure-migration.md for complete patterns and the IMultipleResults blocker.
Step 6: Fix Relationship Loading Patterns
LINQ to SQL lazy-loads via EntitySet<T> / EntityRef<T> by default. EF Core does NOT lazy-load by default.
This is the highest-risk area for subtle runtime bugs:
- Replace
EntitySet<T>→ICollection<T> - Replace
EntityRef<T>→ standard navigation property - Find all navigation property access patterns and add
Include()/ThenInclude()calls - Convert
DataLoadOptions.LoadWith<T>()→Include() - Convert
DataLoadOptions.AssociateWith<T>()→ filtered includes
Code that worked before (order.Customer.Name) will return null / throw NullReferenceException without explicit loading.
See ref/relationship-migration.md for detailed patterns.
Step 7: Migrate Concurrency Handling
If the project uses UpdateCheck attributes on columns, a concurrency strategy decision is needed.
Decision tree:
- Project uses
rowversion/timestampcolumn → use[Timestamp]attribute (straightforward) - Project uses
UpdateCheck.Alwayson all columns → add arowversioncolumn (recommended) or use[ConcurrencyCheck] - Project uses
UpdateCheck.WhenChanged→ no direct equivalent — recommend addingrowversioncolumn UpdateCheck.Never→ those columns simply don't get[ConcurrencyCheck]
Also migrate conflict resolution: ChangeConflictException → DbUpdateConcurrencyException (different resolution API).
See ref/concurrency-and-change-tracking.md for the complete decision tree and API mappings.
Step 8: Fix Query Translation Issues
EF Core is stricter than LINQ to SQL about query translation. The #1 source of runtime breaks:
- Client-side evaluation: LINQ to SQL silently evaluated untranslatable expressions client-side. EF Core throws. Add
.AsEnumerable()before client-side operations. - GroupBy: Complex GroupBy with materialization fails in EF Core
- Take/Skip without OrderBy: EF Core requires explicit
OrderBy - String comparison: Case-sensitivity may differ by provider
- CompiledQuery: Remove
CompiledQuery.Compile()calls — EF Core handles compilation automatically
See ref/query-translation-gotchas.md for the complete list.
Step 9: Validate
- Build all affected projects — zero errors required
- Search for remaining
System.Data.Linqreferences in code - Search for remaining
DataContext,EntitySet,EntityReftype usage - Verify navigation property loading works (test queries that traverse relationships)
- Verify stored procedure calls work
- Verify concurrency conflict handling works
Only proceed to Step 10 after validation passes. The old .dbml and .designer.cs files are useful as a reference if you need to fix issues found during validation.
Step 10: Remove LINQ to SQL Artifacts
MANDATORY — do not skip this step. LINQ to SQL artifacts serve no purpose after migration and will confuse future developers.
Delete these files (verify each exists before deleting):
*.dbmlfiles — the LINQ to SQL O/R Designer model definition (XML). Not used by EF Core.*.dbml.layoutfiles — Visual Studio designer UI layout. Not used by EF Core.- DBML-generated
*.designer.csfiles — the auto-generated DataContext and entity classes. These must have been replaced by new clean files in Step 3. Do NOT delete WinForms/WPF*.Designer.csfiles — only the one that was generated from the.dbml(typically named{DbmlName}.designer.csand containingDataContextinheritance).
Then clean up remaining references:
4. Remove System.Data.Linq assembly reference from the project file (.csproj)
5. Remove using System.Data.Linq and using System.Data.Linq.Mapping statements from all code files
6. Remove any <None Include="*.dbml"> or <Compile Include="*.designer.cs"> entries with <DependentUpon>*.dbml</DependentUpon> or <Generator>MSLinqToSQLGenerator</Generator> from the project file (SDK-style projects handle this automatically; old-style .csproj may need manual cleanup)
How to identify the DBML-generated designer file: It is the .designer.cs file that has a <DependentUpon>SomeName.dbml</DependentUpon> entry in the project file, or that contains a class inheriting from System.Data.Linq.DataContext. Do NOT confuse it with WinForms Form1.Designer.cs files — those are unrelated.
Final check: After cleanup, confirm zero *.dbml, *.dbml.layout files remain and no System.Data.Linq references exist anywhere in the project.
Disambiguation
Do NOT apply this skill to:
System.Linq(LINQ to Objects) — works in modern .NETSystem.Xml.Linq(LINQ to XML) — works in modern .NETSystem.Data.Entity(Entity Framework 6) — separate migration skillLinqToDB(linq2db) — third-party library, different migration path
Success Criteria
- New clean files created for DbContext and entity classes (not rewritten in the old
*.designer.cs) - All LINQ to SQL artifacts deleted:
*.dbml,*.dbml.layout, DBML-generated*.designer.cs - All
System.Data.Linqreferences removed from project file and code - EF Core DbContext replaces all DataContext usage
- All stored procedures migrated to EF Core patterns
- Navigation property loading is explicit (no silent null references)
- Concurrency strategy decided and implemented
- Project builds and queries execute correctly
More skills from the upgrade-agent-plugins repository
View all 19 skillsconverting-to-cpm
migrate .NET projects to Central Package Management
Jul 18.NETMicrosoftMigrationcreating-winforms-custom-controls
create custom WinForms controls
Jul 3.NETWindowsWinUImanaging-winforms-high-dpi-layout
design high-DPI responsive WinForms layouts
Jul 18DesignDesktopUI ComponentsWindowsmanaging-winforms-mvvm
implement MVVM pattern in WinForms
Jul 18.NETWindowsWinUImigrating-aspnet-framework-to-core
migrate ASP.NET Framework to Core
Jul 3.NETASP.NET CoreBackendMigrationmigrating-documentdb-to-cosmos
migrate DocumentDB to Cosmos DB
Jul 3AzureCosmos DBDatabaseMigration
More from Microsoft
View publisherrushstack-best-practices
manage Rush monorepos with best practices
rushstack
Apr 6EngineeringLocal DevelopmentMicrosoftProject Management +1azure-ai-agents-persistent-dotnet
build AI agents with Azure .NET SDK
skills
Jul 3.NETAgentsAzureLLMazure-ai-anomalydetector-java
build anomaly detection applications with Java
skills
May 13AnalyticsAzureData AnalysisJava +2azure-ai-contentsafety-java
build content moderation applications with Azure AI
skills
Jul 7AI InfrastructureAzureJavaSecurityazure-ai-contentsafety-py
detect harmful content with Azure AI Content Safety
skills
Jul 18AzureComplianceLLMMicrosoft +2azure-ai-language-conversations-py
implement conversational language understanding with Python
skills
Jul 18AnalyticsAzureLLMPython