theymleaf get数据_C#.NET 实体与数据库表的设计思路 - 独立思考者

一个合格的项目,最基本之一就是合理的设计数据表与实体类,有些刚刚入门,很难理清数据之间的关系,使得数据表设计得非常不合理;So,我也总结一下,记录下来,也希望对有迷惑的朋友有帮助。

首先,是Model类的设计(ORM使用了EF,Codefirst模式生成的数据表,这里为了方便, 遵循了EF命名约定,就不用再去写配置了);

1、Room(学生宿舍)

 public class Room
    {
        [Key]
        public int Id { get; set; }
        public string Number { get; set; }
        public string Building { get; set; }
        public int MaxPerson { get; set; }
        public virtual ICollection<Student> Persons { get; set; }
    }

2、Student(学生)

  public class Student
    {
        [Key]
        public int Id { get; set; }
        public string Number { get; set; }
        public string Name { get; set; }
        /// <summary>
        /// 是否住校
        /// </summary>
        public bool UseRoom { get; set; } = true;
        public int? RoomId { get; set; }
        public Room Room { get; set; }
    }

3、Product(商品,说明:为了讲解,没有电商SKU的概念了,就先把他看成一个实际的商品)

  public class Product
    {
        [Key]
        public int Id { get; set; }
        public string Number { get; set; }
        public string Name { get; set; }
        public double Weight { get; set; }
        public decimal Price { get; set; }
        /// <summary>
        /// 生产日期
        /// </summary>
        public DateTime ProductDate { get; set; }
        /// <summary>
        /// 有效期至
        /// </summary>
        public DateTime ValidDate { get; set; }
    }

4、Order(订单)

   public class Order
    {
        [Key]
        public int Id { get; set; }
        /// <summary>
        /// 订单编号,业务主键,唯一性
        /// </summary>
        public string Number { get; set; }
        public int BuyerId { get; set; }
        /// <summary>
        /// 订单的客户信息
        /// </summary>
        public Student Buyer { get; set; }
        /// <summary>
        /// 住宿舍的话,,如A栋110号房间;否则手动输入
        /// </summary>
        public string BuyerAddress{get;set;}
        /// <summary>
        /// 订单的商品信息
        /// </summary>
        public virtual ICollection<OrderItem> ProductItems { get; set; }
        /// <summary>
        /// 订单的总价
        /// </summary>
        public decimal Account { get; set; }
    }

5、OrderItem(订单明细)

   public class OrderItem
    {
        [Key]
        public int Id { get; set; }
        /// <summary>
        /// 属于哪一个订单,注意:是一个,与订单的关系是1:N,而且是必须属于某个订单
        /// </summary>
        public Order Order { get; set; }
        public int OrderId { get; set; }
        public int ProductId { get; set; }
        /// <summary>
        /// 商品
        /// </summary>
        public Product Product { get; set; }
        /// <summary>
        /// 数量
        /// </summary>
        public int Qty { get; set; }
        /// <summary>
        /// 单价,为什么用又拿一个字段出来记录?
        /// 1、商品的价格是变动的,而客户下单时的价格是按'现在的商品价格'计算;
        /// 2、个人的话说,订单的价格具有时效性
        /// 已此可理解了,Order里客户的地址字段也是同理
        /// </summary>
        public decimal Price { get; set; }
    }

整理一下关系:

Student与Room:一般现实情况是,一个学生只能住一个宿舍,反过来,一个宿舍可以住多个学生;但有这种情况,有的学生家比较近,不住宿舍,所以:一个学生可以有且最多有1个宿舍(高中数学的味道了),关系为0:N;

Order与OrderItem:订单明细必须属于一个订单,不可能脱离订单存在,其实他们是一个整体,但如果把他们的字段放到一张表里面,想想有多少冗余数据啊,所以一定是1:N;

Student与Order:首先,我这里模拟的是校园内学生点餐场景,所以把学生当做客户。一个订单,必须有客户,且只有一个客户,反过来,客户可以下多个订单,一般的数据表设计,你用我,你就记录我,这是外键的通俗理解,所以也是1:N;

OrderItem与Product:一般的,一条订单明细代表一件商品,订单明细必须指定商品,1:N;

再来看看对应数据表的设计

610f45336848a3deb9328b9e591d0388.png

说明:

1、Id主键、Number编码(编号);

2、OrderItem的Price就是Product的Price数据,下订单就是商品当前的价格,就是按当前价格计算总价,比如你买了2件商品,3天到货,不满意、退一件,这时候这件商品的价格已经发生变化,不可能按现在的价格退,是吧。还是按买的时候的价格来退的,所以这个不是冗余字段,是业务场景下必须的,同理还有Order里的BuyerAddress;

3、个人不推荐用外键,所以把EF自动生成的字段、外键等删了;不影响导航属性的映射,上面说了,遵循了EF的命名规范。据了解,大系统一般是不使用物理外键的,而是提到程序代码中去验证;提交之前去验证导航属性,不仅仅是验证外键是否存在,还有业务逻辑上的,比如场景:B员工填写一个派车申请单,选择的车辆的状态为正常的A1234车(业务需求是只能选正常车哦),估计1分钟之后提交,在选择了车之后与提交之前的这一分钟里,A1234车的司机把车辆的状态改为故障,之后B员工提交上来的派车申请单,也就不仅仅外键验证数据的问题了;这样的业务还是需要设计程序人员多多思考的;

现在,来个控制台添加数据测试吧

static void Main(string[] args)
        {
            MyDbContext dbContext = new MyDbContext();
            //Room r = new Room { Number = "101", Building = "A栋", MaxPerson = 8 };
            //(r);
            //();
            Room r = ();
            #region Student Add
            //List<Student> stuList = new List<Student>();
            //for (int i = 0; i < 5; i++)
            //{
            //    (new Student { Name = "Jack" + i, Number = () + "_" + i, RoomId =  });
            //}
            //(stuList);
            //();
            #endregion

            #region Product Add
            //List<Product> products = new List<Product> {
            //    new Product { Name="西瓜三明治", Number="smz001", Price=3, ProductDate=DateTime.Now, ValidDate=DateTime.Now.AddDays(7), Weight= },
            //    new Product { Name="鸡腿汉堡", Number="hb001", Price=5, ProductDate=DateTime.Now, ValidDate=DateTime.Now.AddDays(7), Weight= },
            //    new Product { Name="八宝粥", Number="bbz001", Price=6, ProductDate=DateTime.Now, ValidDate=DateTime.Now.AddDays(7), Weight= },
            //    new Product { Name="蛋炒饭", Number="dcf001", Price=8, ProductDate=DateTime.Now, ValidDate=DateTime.Now.AddDays(7), Weight= },

            //};
            //(products);
            #endregion
            #region  模拟购物订单 
            using (var tran = ())
            {
                try
                {
                    //客户 Jack2
                    Student buyer = (s => s.Name == "Jack2").FirstOrDefault();
                    //买 八宝粥1份、蛋炒饭2份
                    Product[] items = (a => a.Name == "八宝粥" || a.Name == "蛋炒饭").ToArray();
                    Order order = new Order
                    {
                        BuyerId = buye,
                        //校园点餐,不住宿舍的,手输送货地点(校园内的)
                        BuyerAddress = buyer.UseRoom ? buyer.Room.Building + buyer.Room.Number : "篮球场第1个垃圾桶旁",
                        Number = () + "-" + buye,
                        ProductItems = new List<OrderItem> {
                                         new OrderItem { ProductId=items[0].Id, Price=items[0].Price, Qty=1},
                                         new OrderItem { ProductId=items[1].Id, Price=items[1].Price, Qty=2},
                                    },
                        //订单合计
                        Account = items[0].Price * 1 + items[1].Price * 2,
                    };
                    order = (order);
                    ();
                    (orde);
               
                    ();
                }
                catch (Exception ex)
                {
                    ();
                    throw ex;
                }
            }
            #endregion
        }

数据库表效果

cc8f637d0933e5a8c4b662a9e5fd0de1.png

Ok,基本上的思路就是这样。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值