Files
PowderCoatingLogix/FIX-CUSTOMER-EMAIL-DUPLICATE.md
T
2026-04-23 21:38:24 -04:00

3.4 KiB

Fix Customer Email Duplicate Error

Problem

The unique index on Customers.Email was enforcing global uniqueness (across all companies), but in a multi-tenant system, different companies should be able to have customers with the same email address.

Solution

Change the unique index to be scoped to CompanyId, allowing the same email across different companies while still preventing duplicates within the same company.


Quick Fix (Run SQL Script)

Step 1: Run the SQL Script

  1. Open SQL Server Management Studio
  2. Connect to your testing server
  3. Open the file: fix-customer-email-index.sql
  4. Execute the script

This will:

  • Drop the old global unique index
  • Create new company-scoped unique index
  • Show verification that it worked

Step 2: Test Seeding

  1. Go to your web app: /SeedData
  2. Click "Seed Company Data"
  3. Should work perfectly now!

Alternative: Use EF Migration (For Production Deployment)

If you want to use EF migrations for a cleaner deployment:

From Web Project Directory:

cd src/PowderCoating.Web

# Apply the migration
dotnet ef database update --project ../PowderCoating.Infrastructure

This will apply the migration: FixCustomerEmailIndexForMultiTenancy


What Changed

Before (Old Index):

CREATE UNIQUE INDEX IX_Customers_Email ON Customers (Email)
WHERE [Email] IS NOT NULL

Problem: Only ONE customer across ALL companies can have john.smith@acmemfg.com

After (New Index):

CREATE UNIQUE INDEX IX_Customers_Email ON Customers (CompanyId, Email)
WHERE [Email] IS NOT NULL AND [IsDeleted] = 0

Solution: EACH company can have a customer with john.smith@acmemfg.com


Examples

Now This Works:

CompanyId Email Status
1 john.smith@acmemfg.com OK
2 john.smith@acmemfg.com OK (different company)
1 jane.doe@example.com OK

This Still Prevents Duplicates:

CompanyId Email Status
1 john.smith@acmemfg.com First insert OK
1 john.smith@acmemfg.com DUPLICATE (same company)

Verification

After running the script, verify the index:

-- Check the new index definition
SELECT
    i.name AS IndexName,
    i.is_unique AS IsUnique,
    STRING_AGG(COL_NAME(ic.object_id, ic.column_id), ', ') AS IndexColumns,
    i.filter_definition AS Filter
FROM sys.indexes i
INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
WHERE i.object_id = OBJECT_ID('Customers')
    AND i.name = 'IX_Customers_Email'
GROUP BY i.name, i.is_unique, i.filter_definition

Expected Result:

  • IndexName: IX_Customers_Email
  • IsUnique: 1 (true)
  • IndexColumns: CompanyId, Email
  • Filter: [Email] IS NOT NULL AND [IsDeleted] = 0

Build & Deploy

The migration is already in your code:

src/PowderCoating.Infrastructure/Migrations/
  └─ 20260211160000_FixCustomerEmailIndexForMultiTenancy.cs

When you deploy to production:

dotnet ef database update --project ../PowderCoating.Infrastructure

Will automatically apply this migration.


Summary

Index Fixed - Scoped to CompanyId Multi-Tenancy Safe - Same email OK across companies Duplicate Prevention - Still blocks duplicates within a company Soft Delete Aware - Ignores deleted records

You're ready to seed! 🎉