2

那里

我首先使用 EF 代码按照以下顺序保存数据:过滤器 => 删除 => 添加,运行附加示例(两个线程同时运行),有时我注意到过滤后没有现有记录返回,有时过滤后有两条记录,我认为/预期的是 - 每次过滤器应该有一个现有的记录返回。此外,在保存更改期间还会出现一些异常。

据我所知,EF默认使用Read Committed隔离级别来执行事务,我认为这意味着在过滤期间,共享锁被放在资源上,但是为什么我可以观察到不存在记录或两个现有记录过滤之后,remove 和 add 操作一起应该是原子操作吧?如果我是对的,过滤后应该只有一条记录。

有什么我错过的吗?如何正确处理这种情况?

请帮忙。

另一个问题: 使用 LastUpdated 列作为并发标记,如何正确处理以下情况: 1. 如果数据库中的实体比上下文中的实体更新,则启动另一个线程将实体归档到历史数据库。2. 如果数据库中的实体比上下文中的实体旧,重试保存覆盖数据库中的实体。

我是否正确使用下面的代码来处理此案:

internal void SaveChangesEx()
    {
        bool saveFailed;

        do
        {
            saveFailed = false;
            try
            {

                base.SaveChanges();
            }
            catch (DbUpdateConcurrencyException ex)
            {
                saveFailed = false;
                ex.Entries.ToList().ForEach(entry =>
                {
                    if (entry.State == System.Data.EntityState.Deleted)
                    {
                        var current = base.Set<Customer>().FirstOrDefault();
                        Customer rfqInDb = (Customer)entry.GetDatabaseValues();
                        // If the newer one aready exists, start the archive,                     otherwise, retry by reloading the entity from DB and marking the state as deleted
                        if (current.LastUpdated < customerInDb.LastUpdated)
                        {
                            using (var archiver = new CustomerArchiveDBContext())
                            {
                                                           archiver.RFQS.Add(current);
                                                           archiver.SaveChangesEx();
                            }
                            saveFailed = false;
                        }
                        else
                        {
                            //Refresh the context and retry
                            entry.Reload();
                            entry.State = System.Data.EntityState.Deleted;
                        }
                        }
                        });
                        }
        } while (saveFailed);
    }

脚本:========

CREATE TABLE [dbo].[Customers](
 [FirstName] [nvarchar](20) NOT NULL,
 [LastName] [nvarchar](60) NULL,
 [Company] [nvarchar](250) NULL,
 [Telephone] [nvarchar](20) NULL,
 [LastUpdated] [datetime] NULL
 ) ON [PRIMARY]

代码 ========

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Transactions;
using System.Data.Entity.Validation;
using System.Threading.Tasks;
using System.Threading;
using System.Data.Entity.ModelConfiguration;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;

namespace EFOptimisticConcurrency
{
public abstract class Entity
{
  public int Id { get; set; }
}

public class Customer
    : Entity
{
    public string FirstName { get; set; }

    /// <summary>
    /// Get or set the surname of this customer
    /// </summary>
    public string LastName { get; set; }


    /// <summary>
    /// Get or set the telephone 
    /// </summary>
    public string Telephone { get; set; }

    /// <summary>
    /// Get or set the company name
    /// </summary>
    public string Company { get; set; }

    public DateTime LastUpdated { get; set; }
}

class CustomerEntityConfiguration
    : EntityTypeConfiguration<Customer>
{
    /// <summary>
    /// Create a new instance of customer entity configuration
    /// </summary>
    public CustomerEntityConfiguration()
    {
        //configure keys and properties
        this.HasKey(c => c.FirstName);

        this.Ignore(c => c.Id);

        this.Property(c => c.FirstName)
            .HasMaxLength(20)
            .IsRequired();

        this.Property(c => c.LastName)
            .HasMaxLength(60)
            .IsRequired();

        this.Property(c => c.Company)
            .HasMaxLength(250);

        //this.Property(c => c.LastUpdated).IsConcurrencyToken();

        this.Property(c => c.Telephone)
            .HasMaxLength(20);
        this.ToTable("Customers");
    }
}

public class CustomerContext : DbContext
{
    public DbSet<Customer> Customers { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
        modelBuilder.Configurations.Add(new CustomerEntityConfiguration()); ;
    }
}

public class Program
{
    public static volatile int showStopper = 0;
    static void Main(string[] args)
    {
        var color = Console.ForegroundColor;
        EntityFrameworkProfiler.Initialize();
        Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    Customer customer = new Customer();
                    customer.FirstName = "FirstName";
                    customer.LastName = "Last " + new Random().Next(0, 10000).ToString();
                    customer.Telephone = "686868";
                    customer.Company = "MyCity";
                    customer.LastUpdated = DateTime.Now;

                    if (showStopper == 2)
                    {
                        Console.ReadLine();
                        showStopper = 0;
                    }
                    try
                    {
                        Console.WriteLine("Start the Store => " + customer.LastName + " , " + customer.LastUpdated.ToString());
                        {
                            int i = 0;
                            using (var customerConext = new CustomerContext())
                            {
                                Console.WriteLine("Start the filter 1 => " + customer.Telephone + " , " + customer.LastUpdated.ToString());
                                var matched = customerConext.Customers.Where(c => c.Telephone == "686868" && c.LastUpdated < customer.LastUpdated);
                                foreach (var hit in matched)
                                {
                                    i++;
                                    customerConext.Customers.Remove(hit);
                                }

                                if (i == 2)
                                {
                                    Console.WriteLine("1 - 2 exist, has the problem now");
                                    showStopper = 2;
                                }
                                else if (i == 0)
                                {
                                    Console.WriteLine("1 - 0 exist, has the problem now");
                                    showStopper = 2;
                                }

                                Console.WriteLine("Start Adding 1 => " + customer.LastName + " , " + customer.LastUpdated.ToString());

                                try
                                {
                                    customerConext.Customers.Add(customer);
                                    customerConext.SaveChanges();         
                                    Console.WriteLine("SaveChanges 1 => " + customer.LastName + " , " + customer.LastUpdated.ToString());
                                }
                                catch (Exception ex)
                                {
                                    Console.WriteLine("Exception 1 : " + ex.Message + " => " + customer.LastName + " , " + customer.LastUpdated);
                                    if (ex.InnerException != null)
                                    {
                                        Console.WriteLine("Inner Exception 2 : " + ex.InnerException.Message + " => " + customer.LastName + " , " + customer.LastUpdated);
                                    }
                                }
                            }


                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("Exception 1 " + ex.Message);
                        if (ex.InnerException != null)
                        {
                            Console.WriteLine(ex.InnerException.Message);
                        }
                        showStopper = 2;
                    }
                }
            });


        Thread.Sleep(10000);

        Task.Factory.StartNew(() =>
        {
            while (true)
            {
                Console.ForegroundColor = color;
                try
                {
                    Customer customer = new Customer();
                    customer.FirstName = "FirstName";
                    customer.LastName = "Last " + new Random().Next(0, 10000).ToString();
                    customer.Telephone = "686868";
                    customer.Company = "MyCity2";
                    customer.LastUpdated = DateTime.Now;

                    if (showStopper == 3)
                    {
                        Console.ReadLine();
                        showStopper = 0;
                    }

                    Console.WriteLine("Start the store 2 => " + customer.LastName + " , " + customer.LastUpdated.ToString());
                    {
                        int i = 0;
                        using (var customerConext = new CustomerContext())
                        {
                            Console.WriteLine("Start the filter 2 => " + customer.Telephone + " , " + customer.LastUpdated.ToString());
                            var matched = customerConext.Customers.Where(c => c.Telephone == "686868" && c.LastUpdated < customer.LastUpdated);
                            foreach (var hit in matched)
                            {
                                i++;
                                customerConext.Customers.Remove(hit);
                            }

                            Console.WriteLine("Start Adding 2 => " + customer.LastName + " , " + customer.LastUpdated.ToString());
                            try
                            {
                                customerConext.Customers.Add(customer);
                                customerConext.SaveChanges();
                                Console.WriteLine("SaveChanges 2 => " + customer.LastName + " , " + customer.LastUpdated.ToString());
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine("Exception 2 : " + ex.Message + " => " + customer.LastName + " , " + customer.LastUpdated);
                                if (ex.InnerException != null)
                                {
                                    Console.WriteLine("Inner Exception 2 : " + ex.InnerException.Message + " => " + customer.LastName + " , " + customer.LastUpdated);
                                }

                                showStopper = 2;
                            }
                        }

                        if (i == 2)
                        {
                            Console.WriteLine("1 - 2 exist, has the problem now");
                            showStopper = 2;

                        }
                        else if (i == 0)
                        {
                            Console.WriteLine("1 - 0 exist, has the problem now");
                            showStopper = 2;
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception 2 " + ex.Message);
                    if (ex.InnerException != null)
                    {
                        Console.WriteLine(ex.InnerException.Message);
                    }   
                }
            }
        });


        Console.WriteLine("PRESS ANY KEY TO END");
        Console.ReadLine();
    }
}

}

4

0 回答 0