广告
返回顶部
首页 > 资讯 > 后端开发 > ASP.NET >Entity Framework导航属性介绍
  • 535
分享到

Entity Framework导航属性介绍

2024-04-02 19:04:59 535人浏览 泡泡鱼
摘要

一、主键和外键 关系型数据库中的一条记录中有若干个属性,若其中某一个属性组是能唯一标识一条记录,该属性组就可以称为主键。例如: 学生版(学号、姓名、性别、班级) 其中每个学生的学号是

一、主键和外键

关系型数据库中的一条记录中有若干个属性,若其中某一个属性组是能唯一标识一条记录,该属性组就可以称为主键。例如:

学生版(学号、姓名、性别、班级)

其中每个学生的学号是唯一的,学号就是一个主键。

课程表(课程编号,课程名,学分)

其中课程编号是唯一的,课程编号就是一个主键。

成绩表(学号、课程号、成绩)

成绩表中单独的一个属性无法唯一标识一条记录,学号和课程号的组合才能唯一标识一条记录,所以学号和课程号的属性组是一个主键。

外键

成绩表中的学号不是成绩表的主键,但它和学生表中的学号相对应,并且学生表中的学号是学生表的主键,则称成绩表中的学号是学生表的外键。同理:成绩表中的课程号是课程表的外键。

EntityFramework中的导航属性即外键。下面通过例子讲解如何使用EF的导航属性。

二、导航属性

1、新建产品分类表,语句如下:

CREATE table CateGory
(
  CategoryId int primary key not null identity,
  CategoryName varchar(64)
)

新建产品明细表,其中CategoryId是外键

CREATE TABLE [dbo].[ProductDetail](
    [ProductId] [int] IDENTITY(1,1) NOT NULL,
    [ProductName] [varchar](32) NULL,
    [Price] [decimal](9, 2) NULL,
    [CategoryId] [int] NULL,
PRIMARY KEY CLUSTERED
(
    [ProductId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[ProductDetail]  WITH CHECK ADD  CONSTRAINT [FK_Category] FOREIGN KEY([CategoryId])
REFERENCES [dbo].[Category] ([CategoryId])
GO

ALTER TABLE [dbo].[ProductDetail] CHECK CONSTRAINT [FK_Category]
GO

分别往Category表和ProductDetail表中插入一些测试数据:

--Category表插入数据
INSERT INTO Category (CategoryName)
select '电子产品' uNIOn
SELECT '家用电器' UNioN
SELECT '图书'

--ProductDetail表插入数据
INSERT INTO ProductDetail (ProductName,Price,CategoryId)
SELECT '苹果6s手机',5633,1 UNION
SELECT 'Dell电脑',6998,1 UNION
SELECT '佳能相机',5633,1 UNION
SELECT '海尔洗衣机',1234,2 UNION
SELECT '格力空调',2344,2 UNION
SELECT '美的冰箱',3218,2 UNION
SELECT '白鹿原',342,3 UNION
SELECT 'C#高级编程(第十版)',145,3 UNION
SELECT '平凡的世界',231,3

2、使用DataBase First模式生成edmx文件,然后查看Category表和ProductDetail表相对应的实体的定义

Category表定义:

//------------------------------------------------------------------------------
// <auto-generated>
//     此代码已从模板生成。
//
//     手动更改此文件可能导致应用程序出现意外的行为。
//     如果重新生成代码,将覆盖对此文件的手动更改。
// </auto-generated>
//------------------------------------------------------------------------------

namespace EFNavigateDemo
{
    using System;
    using System.Collections.Generic;

    public partial class Category
    {
        [System.Diagnostics.CodeAnalysis.SuppreSSMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public Category()
        {
            this.ProductDetails = new HashSet<ProductDetail>();
        }

        public int CategoryId { get; set; }
        public string CategoryName { get; set; }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesshouldBeReadOnly")]
        public virtual ICollection<ProductDetail> ProductDetails { get; set; }
    }
}

Category实体类中有一个ProductDetail类型的集合属性,表示是导航属性。

实体类型包含其他实体类型(POCO类)的属性(也可称为导航属性),且同时满足如下条件即可实现延迟加载:

  • 1.该属性的类型必须为public且不能为Sealed。
  • 2.属性标记为Virtual。

ProductDetail实体类定义如下:

//------------------------------------------------------------------------------
// <auto-generated>
//     此代码已从模板生成。
//
//     手动更改此文件可能导致应用程序出现意外的行为。
//     如果重新生成代码,将覆盖对此文件的手动更改。
// </auto-generated>
//------------------------------------------------------------------------------

namespace EFNavigateDemo
{
    using System;
    using System.Collections.Generic;

    public partial class ProductDetail
    {
        public int ProductId { get; set; }
        public string ProductName { get; set; }
        public Nullable<decimal> Price { get; set; }
        public Nullable<int> CategoryId { get; set; }

        public virtual Category Category { get; set; }
    }
}

ProductDetail类里面有一个Category类型的属性。

导航属性实现延迟加载的四种方式:

1、方式一

using (var dbContext = new CategoryEntities())
{
        dbContext.Configuration.LazyLoadingEnabled = true; // 默认是true,针对导航属性
         var categoryList = dbContext.Set<Category>().Where(p => p.CategoryId == 3);
         // 只会在数据库里面查询Category表,不会查询ProductDetail表
         foreach(var category in categoryList)
         {
              Console.WriteLine("CategoryId:"+category.CategoryId+ ",CategoryName:"+category.CategoryName);
              // 这时才会去数据库查询ProductDetail表
              foreach (var product in category.ProductDetails)
              {
                  Console.WriteLine("ProductName:"+product.ProductName);
              }
          }
}

分别在两处foreach循环的地方添加断点,然后运行程序查看数据库执行的sql语句情况:

执行到断点1时:

这时查看数据库监控

继续执行到断点2:

这时在查看数据库监控:

会发现遍历ProductDetails属性时也会查询ProductDetail表。

2、方式二

using (var dbContext = new CategoryEntities())
{
      dbContext.Configuration.LazyLoadingEnabled = false; // 不延迟加载,不会再次查询了
      var categoryList = dbContext.Set<Category>().Where(p => p.CategoryId == 3);
       // 只会在数据库里面查询Category表,不会查询ProductDetail表
       foreach (var category in categoryList)
       {
            Console.WriteLine("CategoryId:" + category.CategoryId + ",CategoryName:" + category.CategoryName);
            // 这时不会去数据库查询了,所以用户全是空的
            foreach (var product in category.ProductDetails)
            {
               Console.WriteLine("ProductName:" + product.ProductName);
            }
       }
}

这时还是采用和上面一样的方法加入断点,只需要查看第二次循环时的数据库监控情况即可:

从上面的截图中看出,如果LazyLoadingEnabled设置为false,将不会再查询ProductDetail表的数据了。

3、方式三

// 显示加载
using (var dbContext = new CategoryEntities())
{
       // 不延迟加载,指定Include,一次性加载主表和从表的所有数据
       var categoryList = dbContext.Set<Category>().Include("ProductDetails").Where(p => p.CategoryId == 3);
       foreach (var category in categoryList)
       {
            Console.WriteLine("CategoryId:" + category.CategoryId + ",CategoryName:" + category.CategoryName);
            // 不会再查询
            foreach (var product in category.ProductDetails)
            {
               Console.WriteLine("ProductName:" + product.ProductName);
            }
       }
}

使用Include()方法会一次性加载所有的数据:

4、方式四

在上面的方式2中把LazyLoadingEnabled设置为false以后就不会再查询ProductDetail表的数据了,这时如果想要查询ProductDetail表的数据该怎么办呢?这时可以使用手动加载,代码如下:

//LoadProperty 手动加载
using (var dbContext = new CategoryEntities())
{
      dbContext.Configuration.LazyLoadingEnabled = false; // 不延迟加载,不会再次查询了
      var categoryList = dbContext.Set<Category>().Where(p => p.CategoryId == 3);
      foreach (var category in categoryList)
      {
            Console.WriteLine("CategoryId:" + category.CategoryId + ",CategoryName:" + category.CategoryName);
            dbContext.Entry<Category>(category).Collection(p => p.ProductDetails).Load();// 集合显示加载
             foreach (var product in category.ProductDetails)
             {
                 Console.WriteLine("ProductName:" + product.ProductName);
             }
       }
}

添加断点:

查看数据库监控:

5、插入数据

对于Category和ProductDetail表如何同时插入数据?先看下面的一段代码:

using (var dbContext = new CategoryEntities())
{
      using (TransactionScope trans = new TransactionScope())
      {
           Category category = new Category()
           {
                CategoryName = "自行车"
           };
           dbContext.Categories.Add(category);
           dbContext.SaveChanges();//category.CategoryId赋值了
           ProductDetail product = new ProductDetail()
           {
                 ProductName = "美利达",
                 Price = 2312,
                 CategoryId = category.CategoryId
            };

            dbContext.ProductDetails.Add(product);
            dbContext.SaveChanges();
            trans.Complete();//提交事务
      }
}

在第一次SaveChanges()后面的一行代码加断点,查看Category信息:

可以看到这是CategoryId已经有值了,查询数据库ProductDetail表:

这时Product的信息已经插入到数据库中了,而且CategordId也是上面生成的CategoryId。

但是这样会导致一种问题存在:如果第一次SaveChanges()成功,第二次SaveChanges()之前报错了,但是程序已经不能回滚了,这样就会导致数据不一致了。使用下面的代码进行优化

using (var dbContext = new CategoryEntities())
{
      using (TransactionScope trans = new TransactionScope())
      {
           Category category = new Category()
           {
                CategoryName = "汽车"
           };

           ProductDetail product = new ProductDetail()
           {
                 ProductName = "上海大众",
                 Price = 190090,
                 CategoryId = category.CategoryId
            };

            category.ProductDetails = new List<ProductDetail>() { product};
            dbContext.Categories.Add(category);
            dbContext.SaveChanges();
            trans.Complete();//提交事务
       }
}

经过这样修改以后可以保证数据的一致性了。这是情况只适合有导航属性的。

示例代码下载地址:点此下载

到此这篇关于Entity Framework导航属性的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持编程网。

--结束END--

本文标题: Entity Framework导航属性介绍

本文链接: https://www.lsjlt.com/news/141828.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Entity Framework导航属性介绍
    一、主键和外键 关系型数据库中的一条记录中有若干个属性,若其中某一个属性组是能唯一标识一条记录,该属性组就可以称为主键。例如: 学生版(学号、姓名、性别、班级) 其中每个学生的学号是...
    99+
    2022-11-13
  • Entity Framework Core相关包的概念介绍与安装
    一、引言 我们以Entity Framework Core 最新版本3.1.1进行讲解,在正式的学习之前,我们第一步是要使用EF Core中的安装包,这时候需要明确的知道到底需要安装...
    99+
    2022-11-13
  • CSS3 Border属性介绍
    通过边框属性,我们可以实现一些类似按钮或者背景图片的替代效果。因为大量的图片素材对网页的加载速度影响也很大,但是由于现在的浏览器对css3的兼容与支持各有不同,所以现在要用css替代 配合图片达到的效果还是不太现实。 言归正转,来看看css...
    99+
    2023-01-31
    属性 Border
  • CSS3 Background 属性介绍
    与border类似,ie对新的background属性都是不支持的。多的就不说了,来看看,新的background 属性吧。 1、background-origin  控制背景图片区域 三个取值,由外向内分别为: border-b...
    99+
    2023-01-31
    属性 Background
  • CSS3 Color属性介绍
    通常我们使用css控制颜色时,均采用16进制的RGB模式,如 color:#ff0000; 这边先介绍一下几种色彩模式及取值规则 HSL色彩模式是工业界的一种颜色标准,是通过对色调(H)、饱和度(S)、亮度(L)三个颜色通道的变化以及它们相...
    99+
    2023-01-31
    属性 Color
  • WPF框架Prism中导航Navigation用法介绍
    使用场景 在普遍的业务场景当中, 必不可少的是页面切换, 而Prism就可以使用Navigation功能来进行页面导航, 在不同的场景当中会有各种用法, 例如在切换页面验证、传递参数...
    99+
    2022-11-13
  • Blazor路由与页面导航开发介绍
    在 Blazor 中,应用中的每个页面都是一个组件,通常在 razor 文件中定义,具有一个或多个指定路由。 路由大多数发生在客户端,而不涉及特定的服务器请求。 浏览器首先发出对应用...
    99+
    2022-11-13
  • HTML表格属性介绍
    本篇内容介绍了“HTML表格属性介绍”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! ...
    99+
    2022-10-19
  • Kubernetes的pod属性介绍
    这篇文章主要讲解了“Kubernetes的pod属性介绍”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Kubernetes的pod属性介绍”吧!我们可以首先使用kubectl get pod...
    99+
    2023-06-06
  • VBS的Attributes属性介绍
    这篇文章主要介绍“VBS的Attributes属性介绍”,在日常操作中,相信很多人在VBS的Attributes属性介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”VBS的Attributes属性介绍”的疑...
    99+
    2023-06-08
  • 详解EFCore中的导航属性
    目录    1 单独使用Include  2 主清单使用Include  3 ThenInclude用法  4 IncludeFilter用法  5 特殊情况  ...
    99+
    2022-11-11
  • EFCore中的导航属性是什么
    本篇文章给大家分享的是有关EFCore中的导航属性是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。    1 单独使用Include  在介绍这个方法之...
    99+
    2023-06-08
  • HTML5中的autofocus属性介绍
    本篇内容介绍了“HTML5中的autofocus属性介绍”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!这里...
    99+
    2022-10-19
  • HTML5中placeholder属性的介绍
    这篇文章主要介绍“HTML5中placeholder属性的介绍”,在日常操作中,相信很多人在HTML5中placeholder属性的介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大...
    99+
    2022-10-19
  • python中的__dict__属性介绍
    将字典转换成对象的小技巧: bokeyuan = {"b": 1,                 "o": 2,                 "k": 3,          ...
    99+
    2022-11-10
  • html的缩进属性介绍
    今天小编给大家分享的是html的缩进属性介绍,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获的哦。 在html中,缩进属性是“t...
    99+
    2022-10-19
  • VBscript属性的功能介绍
    本篇内容主要讲解“VBscript属性的功能介绍”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“VBscript属性的功能介绍”吧!VBScript 属性描述语言元素返回或设置与一个错误相关联的描...
    99+
    2023-06-08
  • C#属性的详细介绍
    这篇文章主要讲解了“C#属性的详细介绍”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C#属性的详细介绍”吧!C# 属性示例代码class TimePeriod  ...
    99+
    2023-06-17
  • Android 系统属性(SystemProperties)介绍
    我们在开发过程中有时需要使用系统属性,例如获取系统软件版本,获取设备名名称等,有时也需要设置自定义属性。本文将基于Android 10(Q)介绍Android系统属性(以下简称prop)使用,下文围绕...
    99+
    2023-09-03
    android
  • React路由规则定义与声明式导航及编程式导航分别介绍
    目录1. 路由使用2. 声明式导航3. 编程式导航1. 路由使用 安装路由模块: 路由模块不是react自带模块,需要安装第3方模块: yarn add react-router-d...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作