views:

59

answers:

0

I'm having issues when trying to insert nvarchar values in sql server with a linq-to-sql + c# program. Here is the code:

public partial class Recipient
{
    private static object _recipientLock = new object();

    public static Recipient Find(string email, string displayName, 
                                  MyDataContext db)
    {
        try
        {
            return db.Recipients
                .Where(r => r.Email == email.ToLowerInvariant().Trim())
                .ToList()
                .Single(r => r.DisplayName.ToLowerInvariant().Trim() ==
                      displayName.Truncate(195).ToLowerInvariant().Trim()); ;
        }
        catch (InvalidOperationException ioe)
        {
            throw new EntityNotFoundException(typeof(Recipient), email + ";" +
                      displayName, ioe);
        }
    }

    public static Recipient FindOrCreate(MailAddress mailAddress, 
                                       MyDataContext db)
    {
        try
        {
            return Recipient.Find(mailAddress.Address, 
                                       mailAddress.DisplayName, db);
        }
        catch (EntityNotFoundException)
        {
            lock (_recipientLock)
            {
                try
                {
                    return Recipient.Find(mailAddress.Address, 
                                              mailAddress.DisplayName, db);
                }
                catch (EntityNotFoundException)
                {
                    using (var tempDB = 
                      SherWebArchivingClientDataContext.New(db.OrganizationName))
                    {
                        tempDB.Recipients.InsertOnSubmit(new Recipient()
                        {
                            DisplayName = 
                                 mailAddress.DisplayName.Truncate(195).Trim(),
                            DomainName = 
                                 mailAddress.Host.ToLowerInvariant().Trim(),
                            Email = 
                                 mailAddress.Address.ToLowerInvariant().Trim(),
                        });
                        tempDB.SubmitChanges();
                    }
                }
            }
            return Recipient.Find(mailAddress.Address, 
                                   mailAddress.DisplayName, db);
        }
    }
}

This code is used to list a number of unique email recipients based on the email address and display name. The sql server table has a unique key constraint on both fields. Here is the table definition:

CREATE TABLE [Recipients](
[ID] INT NOT NULL PRIMARY KEY IDENTITY(1,1),
[Email] NVARCHAR(255) NOT NULL,
[DisplayName] NVARCHAR(195) NULL,
[DomainName] NVARCHAR(255) NOT NULL);

The problem is that sometimes I'm getting unique key violations on the DisplayName column. The code is run in a multi-threaded way, but the problem is probably not caused by two threads trying to insert the same value.

When looking at the DisplayName that is inserted, it is made of special characters from foreign language (japanese or hebraic from the tracked cases).

My understanding is that the Find() does not return the existing entry, so the insert violates the unique key constraint.

What I already tried: - In Find(), tried to compare the DisplayNames on database-side. (removed the ToList()).

My environment:

  • .net 3.5 SP1
  • Sql Server 2008
  • Windows server 2008 latest release

I could bring all this logic in a stored procedure, even though I'm not sure it will definitely solve the problem... I could also handle this unique key violation, but how can I retrieve the original record that blocked the insert?

Thanks for any insights or advice.