更新实体


  Fireasy 提供了一组 Update / UpdateAsync 方法来修改数据,并且是实时生效的。


1、更新单一实体

  Update / UpdateAsync 方法用于将对一个实体对象的更改保存到库中。

[TestMethod]
public void TestUpdate()
{
    using (var db = new DbContext())
    {
        var order = db.Orders.FirstOrDefault();
        order.ShipName = "fireasy";
        db.Orders.Update(order);
    }
}

[TestMethod]
public async Task TestUpdateAsync()
{
    using (var db = new DbContext())
    {
        var order = await db.Orders.FirstOrDefaultAsync();
        order.ShipName = "fireasy";
        await db.Orders.UpdateAsync(order);
    }
}

  对单一实体的更新,只有修改过的属性才会被更新到库中,这得益于实体内部的状态管控机制。因为 使用 FirstOrDefault / FirstOrDefaultAsync 查询出的实体状态是 Unchanged,一旦修改属性后,状态变成了 Modified,同时它会记录下被修改的属性,在解析出来的的 SQL 语句中,只会对此字段进行更新。因此,我们也可以把某一属性值修改为 null,在非状态管控机制下,这是不可能完成的。

[TestMethod]
public void TestUpdate()
{
    using (var db = new DbContext())
    {
        var order = db.Orders.FirstOrDefault();
        order.ShipName = null;
        db.Orders.Update(order);
    }
}

  但下面的情况就会非常糟糕,原因是实体是 new 的,和 Insert 一样,它不能记录下哪些属性被赋过值。

[TestMethod]
public void TestUpdateByNewEntity()
{
    using (var db = new DbContext())
    {
        var order = new Orders { OrderID = 11092 };
        order.ShipName = "fireasy";
        db.Orders.Update(order);
    }
}

  跟踪 SQL 你会发现似乎一切正常,但是这种更新是取非 null 的属性进行更新,对于 intlongDateTime 等非空类型就要非常小心了,相应的数据会被清零。

  我们可以采取和 Insert 类似的办法,即使用 New 或 Wrap 静态方法。

[TestMethod]
public void TestUpdateByWrap()
{
    using (var db = new DbContext())
    {
        var order = Orders.Wrap(() => new Orders { OrderID = 11092 });
        order.ShipName = "fireasy";
        db.Orders.Update(order);
    }
}

2、使用 lambda 表达式更新

  除了针对某一实体更新,Fireasy 还提供了使用 lambda 表达式对符合条件的实体进行批量更新,由于不需要将符合条件的实体获取出来进行逐一,因此这在很多场合会显得非常适用。返回值为更新的数据条数。它的原理与使用 lambda 插入实体时是一样的。

  以下的示例中,只会将符合条件的数据的 Freight 更新为 1。

[TestMethod]
public void TestUpdateByExpression()
{
    using (var db = new DbContext())
    {
        db.Orders.Update(() => new Orders { Freight = 1 }, s => s.OrderDate >= DateTime.Now);
    }
}

3、使用初始化委托更新

  这一组方法是使用一个委托,对实体对象的属性进行赋值,它同时弥补了前两种方法上的缺陷,从使用的方便性和代码运行性能上来说都是最优的。

[TestMethod]
public void TestUpdateByInitializer()
{
    using (var db = new DbContext())
    {
        db.Customers.Update(c =>
        {
            c.CustomerID = "F3";
            c.CompanyName = "fireasy";
            c.City = "kunming";
        }, s => s.OrderDate >= DateTime.Now);
    }
}

  委托参数 c 实际上已经是一个 AOP 代理对象了,赋值后能够追踪其属性的状态。


4、使用计算器更新

  在某些时候,需要对值进行递增修改,常见的做法是先获取实体,修改属性后再 Update。Fireasy 提供了一种更为快捷的更新方法:计算器。 与上节的 Update 比较类似,只是 lambda 表达式多了一个参数,下例中,Freight 在原基础上乘以 100。

[TestMethod]
public void TestUpdatByCalculator()
{
    using (var db = new DbContext())
    {
        db.Orders.Update(s => new Orders { Freight = s.Freight * 100 }, s => s.OrderDate >= DateTime.Now);
    }
}

5、使用属性过滤更新

  见 属性过滤