插入实体
Fireasy 是类似于 linq to sql
的风格,不像 Entity Framework
在集合里添加实体,最后调用 SaveChanges 方法来持久化。Fireasy 提供了一组 Insert / InsertAsync 方法来插入数据,并且是实时生效的。
1、插入单一实体
Insert / InsertAsync 接收一个实体对象,将其插入到库中。
[TestMethod]
public void TestInsert()
{
using (var db = new DbContext())
{
var customer = new Customers
{
CustomerID = "F1",
CompanyName = "fireasy",
City = "kunming"
};
db.Customers.Insert(customer);
}
}
[TestMethod]
public async Task TestInsertAsync()
{
using (var db = new DbContext())
{
var customer = new Customers
{
CustomerID = "F1",
CompanyName = "fireasy",
City = "kunming"
};
await db.Customers.InsertAsync(customer);
}
}
该方法返回一个 int 类型的值,如果主键的 GenerateType 为AutoIncrement,那么该方法将返回自动生成的编号(注意:仅主键类型为 int 时返回),否则为影响的记录条数。如果要取主键值,可以取实体的主键值。如下所示:
[TestMethod]
public void TestInsertAndRetPk()
{
using (var db = new DbContext())
{
var order = new Orders
{
CustomerID = "ALFKI",
};
var ret = db.Orders.Insert(order);
//测试返回值是否与主键值一致
Assert.AreEqual(ret, order.OrderID);
}
}
必须注意的是,如果使用 new 构造实体,它将不受状态管控,所有非 null 的属性将插入到库中,这样造成的影响是,诸如 int、long、DateTime 类型的属性,会将其默认值直接插入到库中。
应对的方法可以采用实体类的静态函数 New 和 Wrap。
New 函数是构造一个经过代理加工后(AOP
)的实体对象,因此在对属性赋值的时候,它是受状态管控的。
[TestMethod]
public void TestInsertByNew()
{
using (var db = new DbContext())
{
var customer = Customers.New();
customer.CustomerID = "F2";
customer.CompanyName = "fireasy";
customer.City = "kunming";
db.Customers.Insert(customer);
}
}
Wrap 是封装一个 lambda
表达式,表达式必须成员绑定,它通过分析成员绑定表达式(MemberInitExpression
),找出需要插入的属性。
[TestMethod]
public void TestInsertByWrap()
{
using (var db = new DbContext())
{
var customer = Customers.Wrap(() => new Customers
{
CustomerID = "F3",
CompanyName = "fireasy",
City = "kunming"
});
db.Customers.Insert(customer);
}
}
2、使用 lambda 表达式插入
鉴于上例中存在的对象状态的问题,Insert / InsertAsync 还提供另外一组方法,它接收一个 lambda
表达式,其原来是解析成员绑定表达式(MemberInitExpression
)中对成员的赋值,构建出一个具有状态的实体对象。因此,它对于字段的写入是按需的、可控的。
[TestMethod]
public void TestInsertByExpression()
{
using (var db = new DbContext())
{
db.Customers.Insert(() => new Customers
{
CustomerID = "F3",
CompanyName = "fireasy",
City = "kunming"
});
}
}
使用这组方法时应注意,lambda
表达式中的赋值不能出现太过复杂的非常量表达式,比如方法等等。以下的示例中,将不能正确地解析出属性的值。
[TestMethod]
public void TestInsertByExpression()
{
using (var db = new DbContext())
{
var customerId = "F3";
db.Customers.Insert(() => new Customers
{
CustomerID = customerId, //支持变量或参数
CompanyName = GetCompanyName(), //无法解析方法表达式
City = "yunnan" + "kunming", //无法解析方法表达式
EmployeeAmount = 34 * 100 //无法解析运算表达式
});
}
}
private string GetCompanyName()
{
return "fireasy";
}
另外,该方法不支持带参数的构造表达式(NewExpression
),也不能接收一个实体对象(ConstantExpression
)。如:
[TestMethod]
public void TestInsertByExpression()
{
using (var db = new DbContext())
{
//以下方法是不支持的
db.Customers.Insert(() => new Customers("F3"));
//以下方法是不支持的
var customer = new Customer { CustomerId = "F3" };
db.Customers.Insert(() => customer);
}
}
3、使用初始化委托插入
这一组方法是使用一个委托,对实体对象的属性进行赋值,它同时弥补了前两种方法上的缺陷,从使用的方便性和代码运行性能上来说都是最优的。
[TestMethod]
public void TestInsertByInitializer()
{
using (var db = new DbContext())
{
db.Customers.Insert(c =>
{
c.CustomerID = "F3";
c.CompanyName = "fireasy";
c.City = "kunming";
});
}
}
委托参数 c 实际上已经是一个 AOP
代理对象了,赋值后能够追踪其属性的状态。
4、使用属性过滤插入
见 属性过滤。