设为首页 加入收藏

TOP

某电商平台开发记要(一)
2019-09-17 17:48:55 】 浏览:136
Tags:电商 平台 开发

本文是博主在开发某电商平台项目的一些杂项记录,方便自己和团队同事查阅,偏向于具体技术或应用的细节和个人理解,但也未必非常具体。文中未提的更多内容可能会另起篇章。


导航属性——EF实体关系fluent配置

实体关系——一对一[或零],一对多,多对多——对应到数据库就是外键约束。为了性能及数据迁移考虑,在事务性要求不高的情形中,我们一般都禁用外键,但是EF中仍可保留实体关系以方便编程。

本文基于EF6.1.3版本。

EF中有两类关系:Independent association 和 Foreign Key association。在实体定义时可以看出它们的不同。

 1 //这是Independent association
 2 public class Order
 3 {
 4     public int ID { get; set; }
 5     public Customer Customer { get; set; } // <-- Customer object
 6     ...
 7 }
 8 
 9 //这是Foreign key association
10 public class Order
11 {
12     public int ID { get; set; }
13     public int CustomerId { get; set; }  // <-- Customer ID
14     public Customer Customer { get; set; } // <-- Customer object
15     ...
16 }

很明显看到两者的差别就在于是否存在外键属性,EF会按照默认规则构建或寻找到正确的外键字段。我们也可以显式配置外键,两种方法:

1 Map(m=>m.MapKey("CustomerId"));
2 HasForeignKey(m=>m.CustomerId);

Map适用于Independent association,而HasForeignKey用于Foreign Key association。如果在Foreign Key association时使用Map,将会抛出:“CustomerId:Name:类型中的每个属性名必须唯一,已定义属性名CustomerId”的错误。

需要注意的是,一对一的实体关系,EF并未提供HasForeignKey指定外键。why?EF团队认为,既然两个实体是一一对应的关系,那么可以由一个主键标识两个实体,so,will use its primary key as the foreign key。。。也是醉了。如果硬要指定一个外键的话,对于Independent association还好,我们可以用Map,但是Foreign Key association就悲剧了。可以使用WithMany()这个hack,但比较别扭,个人是不推荐这种方法。详情可参看One to zero-or-one with HasForeignKey。尝试使用[ForeignKey]特性,也会报错[比如]:系“CategoryCashDepositInfo_CategoriesInfo”中 Role“CategoryCashDepositInfo_CategoriesInfo_Source”的多重性无效。因为 Dependent Role 属性不是键属性,Dependent Role 多重性的上限必须为“*”。so,一对一实体的外键也必须是它的主键,尼玛。不幸遇到这种问题,在项目初期(一般来说踩坑都是比较早的),最好的方式还是改变数据结构以适应EF要求,毕竟它这么要求确实有道理。

另:若一实体没有导航属性,但是另一实体包含该实体集合的属性,那么在生成数据库时,EF也会自动为它们生成外键约束。

在增删改实体时,若有上下文跟踪,则连带着实体的导航属性对应的数据也一并会受影响,比如在更新父子表时,不需要自己写单独更细两张表的代码,EF都帮我们处理好了。举个典型例子:

public class Journal
{
    public int ID { get; set; }
    public decimal Amount { get; set; }
    public int OrderID { get; set; }
    public BillOrder Order { get; set; }

}

public class BillOrder
{
    public int ID { get; set; }
    public string Title { get; set; }
}

using (var context = new Entities())
{
    var order = new BillOrder { Title="test order" };
    //OrderID =order.ID 有无都一样,最后数据表里字段会赋予实际值
    var j = new Journal { Amount=10, Order= order,OrderID =order.ID };
    context.Journals.Add(j);//只要add主类即可
    context.SaveChanges();
}
View Code

更多可参看 MVC3+EF4.1学习系列(六)-----导航属性数据更新的处理

待验证:一对一时,导航属性有没有延迟加载一说?另导航属性链查询细节,比如Comment.OrderItem.OrderInfo.PayDate,其中OrderItem是Comment的导航熟悉,OrderInfo是OrderItem的导航属性,这个时候SQL查询步骤是怎样的呢?——一对一时,不会自动加载,即获取父对象后,导航属性对应的子对象一直为null(不管后续有没有用到,用到的话会抛出NullReferenceException),但是在获取父对象时使用Include显式加载子对象,是可以的。同其它导航属性一样,之前测试出现无法加载是因为忘记给导航属性前面添加virtual关键字了。。。

导航属性的删除更新操作需要特别注意,如果直接将导航属性赋值为新对象,保存后,数据表中将新增记录,而原记录仍然存在,原因显而易见,这里不说了。

1 var order = context.BillOrders.First();
2 context.Set<BillOrderSub>().RemoveRange(order.Items);//这步不能少
3 var items = new int[] { 1, 1, 1 }.Select(i => new BillOrderSub()).ToArray();
4 order.Items = items;
5 context.SaveChanges();

注意要使用DbSet定义的RemoveRange之类的方法,否则会报下面的错误

另:给父对象设置EntityState,并不会自动给导肮实体赋予相同Entity

首页 上一页 1 2 3 4 5 6 7 下一页 尾页 1/7/7
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇<大话设计模式>笔记 下一篇SNF快速开发平台成长史V4.5-Sprin..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目