zoukankan      html  css  js  c++  java
  • Entity Framework 6 Recipes 2nd Edition(9-6)译->管理断开时的并发

    9-6. 管理断开时的并发

    问题

    想要确保只接受在WCF客户端并发令牌未被修改的实体。

    解决方案

    我们有一个如Figure 9-6所示的模型.

     

    Figure 9-6订单实体模型

    我们想通过WCF服务来更新一个order ,而要确保这个order 在我们上次取回后没有发生过其它修改。

    稍后我们将演示两个不同的方式.两种都用一个TimeStamp列作并发控制。

    1. 新建一个WCF服务库,右击解决方案,选择“新建项目”,选择WCF ➤ WCF 服务库,并命名为Recipe6.

    2. 右击这个项目,选择“添加” ➤“新建项” ,选择 数据➤ ADO.NET实体数据模型.在向导中选择Order表. 在EF模型设计图中,右击TimeStamp 属性, select “属性“, 把“并发模式”设为Fixed.

    3. 用Listing 9-30里的代码定义IService1.cs 文件里的服务

    Listing 9-30. Our WCF Service Contract

        [ServiceContract]

        public interface IService1

        {

            [OperationContract]

            Order InsertOrder();

            [OperationContract]

            void UpdateOrderWithoutRetrieving(Order order);

            [OperationContract]

            void UpdateOrderByRetrieving(Order order);

    }

    4. 用Listing 9-31的代码实现Service1.cs 文件里的服务。

    Listing 9-31. The Implementation of Our Service Contract

    public class Service1 : IService1

        {

            public Order InsertOrder()

            {

                using (var context=new EFRecipesEntities())

                {

                    //删除之前的测试数据

                    context.Database.ExecuteSqlCommand("delete from chapter9.[order]");

                    var order = new Order { Product = "Camping Tent", Quantity = 3, Status = "Received" };

                    context.Orders.Add(order);

                    context.SaveChanges();

                    return order;

                }

            }

     

            public void UpdateOrderWithoutRetrieving(Order order)

            {

                using (var context=new EFRecipesEntities())

                {

                    try

                    {

                        context.Orders.Attach(order);

                        if (order.Status=="Received")

                        {

                            context.Entry(order).Property(x => x.Quantity).IsModified = true;

                            context.SaveChanges();

                        }

                    }

                    catch (OptimisticConcurrencyException ex)

                    {

                        //处理并发异常

                    }

                }

            }

     

            public void UpdateOrderByRetrieving(Order order)

            {

                using (var context=new EFRecipesEntities())

                {

                    //从数据库中获取当前实体

                    var dbOrder = context.Orders.Single(o => o.OrderId == order.OrderId);

                   //执行并发检查

                    if (dbOrder!=null&&StructuralComparisons.StructuralEqualityComparer.Equals(order.TimeStamp,dbOrder.TimeStamp))

                    {

                        dbOrder.Quantity = order.Quantity;

                        context.SaveChanges();

                    }

                    else

                    {

                        //处理并发问题

                    }

                }

            }

    }

    5. 为测试服务,我们在解决方案里创建一个控制台应用程序.在服务项目上右击,选择“调试” ➤启动新实例,然后在控制项目里添加对这个服务的引用。控制台项目代码如Listing 9-32 所示.

    Listing 9-32. The Client We Use to Test Our WCF Service

        class Program

        {

            static void Main(string[] args)

            {

                var service = new ServiceReference1.Service1Client();

                var order = service.InsertOrder();

                order.Quantity = 5;

                service.UpdateOrderWithoutRetrieving(order);

                order = service.InsertOrder();

                order.Quantity = 3;

                service.UpdateOrderByRetrieving(order);

            }

    }

    如果在Main() 方法前设置断点,逐语句执行,将会看到代码运行入服务端。

    它是如何工作的?

    InsertOrder() 方法(见Listing 9-31) 删除之前的测试数据,插入一个新的order, 并且返回包含正确ID值和TimeStamp的order.在我们客户端,我们用两个略微不同的方式来更新这个order.

    第一种用UpdateOrderWithoutRetrieving()方式:先把从客户端传过来的order 附加Attach()到DbContext,然后判断order状态是否为“Received”,如果是我们把实体 Quantity 属性状态设为 modified然后调用

    SaveChanges(). EF会生成一个更新SqL语句,它的Where子句里包含OrderId和TimeStamp.如果SaveChanges()前数据库中该条数据被修改过,则会产生异常(存储区更新、插入或删除语句影响到了意外的行数(0)。实体在加载后可能被修改或删除。刷新 ObjectStateManager 项。)。我们用try,catch来捕获异常. 这样就可以保证客户端提交过来的Order在运行InsertOrder() 之后,数据库里对应记录的数据未被修改过. 其实我们可以在保存前先进行并发检查,从客户端回传的order的TimeStamp属性值与数据库的值比较。这就是UpdateOrderByRetrieving() 方法里采用的方式。

    附:创建示例用到的数据库的脚本文件

    kid1412声明:转载请把此段声明完整地置于文章页面明显处,并保留个人在博客园的链接:http://www.cnblogs.com/kid1412/(可点击跳转)。

  • 相关阅读:
    待解决问题集
    官方
    jsp 页面接收另一个页面传递过来的数据
    页面无法通过“${ctx}” 拿到值
    自定义 UsernamePasswordToken 报错 java.lang.ClassCastException: org.apache.shiro.authc.UsernamePasswordToken cannot be cast to
    springboot+mybatis map集合映射字段,当sql字段返回值为空时 不映射的问题
    java实现读写服务器文件
    前端模板免费下载网站
    The connection string contains invalid user information. If the username or password contains a colon (:) or an at-sign (@) then it must be urlencoded 解决方法
    springBoot -mongodb 小坑
  • 原文地址:https://www.cnblogs.com/kid1412/p/5142428.html
Copyright © 2011-2022 走看看