• 1.对属性使用约定和配置


    1.在Code First中使用属性

      Length字长

    Convention默认规则 max (type specified by database)max(类型由数据库指定)
    Data Annotation MinLength(nn)MaxLength(nn)StringLength(nn)
    Fluent Entity<T>.Property(t=>t.PropertyName).HasMaxLength(nn)

      字长用于描述数组的长度。包括对字符串和byte数组。

      Code First的默认规则string 或者byte数组的长度应为最大。根据不同的数据库类型确定在数据库最终的类型。对SQL Server而言,string 会生成nvarchar(max),而byte数组会生成varbinary(max).

      数据类型

    Convention默认规则

    The default column data type is determined by the database provider you are using. For SQL Server some example default data

    types are:默认的列数据类型由数据库决定,对SQL Server而言如下:String : nvarchar(max)Integer:intByte Array:varbinary(max)Boolen:bit

    Data Annotation Column(TypeName="XXX")
    Fluent Entity<T>.Property(t=>t.PropertyName).HasColumnType("XXX")

      可空性和必需项配置

    Convention默认规则 Key Properties : not null in database键属性:在数据库中为非空Reference Types (String, arrays): null in the database引用类型(String,数组):在数据库中可空Value Types (all numeric types, DateTime, bool, char) : not null in database值类型(所有数字类型,日期,布尔,字符):在数据库为非空Nullable<T> Value Types : null in databaseNullable<T>值类型(可空类型):在数据库可空
    Data Annotation Required
    Fluent Entity<T>.Property(t=>t.PropertyName).IsRequired

    2.映射键

    Convention默认规则 Properties named Id属性名为IdProperties named [TypeName] + Id属性名为[类型名]+Id
    Data Annotation Key
    Fluent Entity<T>.HasKey(t=>t.PropertyName)

      EF框架要求每个实体都有一个键。这个键用于上下文以保持每个独立对象的跟踪。键是唯一的而且经常由数据库生成。Code First默认规则作出了同样的预设。

      回忆一下由Destination和Lodging类生成的数据库,DestinationId和LodgingId的整型字段都被标记为主键和非空字段。如果进一步观察二者的列属性,你会发现这些字段是自增长的标识字段,如图3-1所示,这是默认规则将整型量作为主键来管理。

      

    • 使用Data Annotations配置Key

       Data Annotation标识一个键只需要简单的一个Key.Key特性位于System.ComponentModel.DataAnnotations.dll,由于它已经被添加到了.Net4之中,也被其他API所使用(如ASP.Net MVC使用的Key).如果你的项目尚未包含此程序集的引用,你就不能添加它。对这个特定的特性不需要引用EntityFramwork.dll。

    public   class  Trip
    {
        [Key]
        public Guid Identifier {
            get;
            set;
        }
        public DateTime StartDate {
            get;
            set;
        }
        public DateTime EndDate {
            get;
            set;
        }
        public decimal CostUSD {
            get;
            set;
        }
    }
    View Code
    •   在Flurent API中使用HasKey来配置Key属性

      e.g.1  The HasKey Fluent configuration in OnModelCreating

      modelBuilder.Entity < Trip > ().HasKey(t = >t.Identifier)

      e.g.2 HasKey inside of an EntityTypeConfiguration class

      HasKey(t = >t.Identifier)

      HasKey(t = >new {t.id,t.name})   //组合主键

    3.配置数据库生成的属性

    Convention默认规则 Integer keys:Identity整型键值:标识列
    Data Annotation DatabaseGenerated(DatabaseGeneratedOption)
    Fluent Entity<T>.Property(t=>t.PropertyName).HasDatabaseGeneratedOption(DatabaseGeneratedOption)

    4.为开放式并发环境配置时间戳或行版本字段

    Convention默认规则 None无
    Data Annotation TimeStamp
    Fluent Entity<T>.Property(t=>t.PropertyName).IsRowVersion()

       EF框架从第一版本开始就支持开放式并发环境。 Programming Entity Framework 这本书的第二版在第23章深入探讨了开放式并发。在这里我我们教你如何配置类映射到RowVersion(或称作TimeStamp,时间戳)字段,同时通知EF框架在进行更新或删除数据库操作时使用这些字段进行并发检查。

      一个类只能有一个属性可以配置为TimeStamp特性。

      RRowVersion和TimeStamp是两个具有相同类型的项。Sql Server使用TimeStamp,而其他数据库使用更恰当的名称为RowVersion.d SQL Server2008中,timestamp数据类型也调整为rowversion,但是大多数工具(如Sql Server Management Studio,vs等)仍然显示为timestamp.

    • 使用Data Annotations配置时间戳

      并非任何属性都可以映射到一个timestamp数据库类型。必须是byte数组才可以。配置过程很简单,将TimeStamp特性加到Trip和Personal类中的下列属性中。

    [Timestamp]
    public byte[] RowVersion {get; set;}

      任何时候行内数据被修改时数据库都会自动为此属性创建新值。但TimeStamp不仅影响数据库的映射,还会导致属性被EF框架视作并发的令牌。如果你使用EDMX文件,这就等同于设置了一个属性的ConcurrencyMode(并发模式)。EF框架在执行插入、更新或删除数据库时,就会考虑并发字段,返回每个INSERT和UPDATE更新数据库的值,并传回到每个UPDATE和DELETE的相关属性的原始位置。

      默认情况下,Code First并不识别时间戳属性,因此没有默认约定行为,获得此行为必须配置此属性。

    • 使用Fluent API配置TimeStamp/RowVersion

      modelBuilder.Entity < Person > ().Property(p = >p.RowVersion).IsRowVersion();

      Property(p = >p.RowVersion).IsRowVersion();

    5.配置并发非时间戳字段

    Convention默认规则 None无
    Data Annotation ConcurrencyCheck
    Fluent Entity<T>.Property(t=>t.PropertyName).IsConcurrencyToken()

      一个不太常见的方式是并发检查是通过字段为非行版本类型进行的。例如,许多数据库可能并没有行版本数据类型。因此你不能指定一个行版本属性,但你仍需要对一个或多个数据库字段进行并发检查。

    • 使用Data Annotations配置开放式并发
    public class Person {
        public int PersonId {
            get;
            set;
        } [ConcurrencyCheck]
        public int SocialSecurityNumber {
            get;
            set;
        }
        public string FirstName {
            get;
            set;
        }
        public string LastName {
            get;
            set;
        }
    }
    View Code
    private static void UpdatePerson() {
        using(var context = new BreakAwayContext()) {
            var person = context.People.FirstOrDefault();
            person.FirstName = "  Rowena  ";
            context.SaveChanges();
        }
    }

      正如您在Trip.RowVersion字段中看到的(代码3-10),当一个更新或删除请求发送以数据库时,SLQ语句(见代码3-13)不仅查找匹配的Key(PersonId),还要匹配原始并发字段值(SocialSecurityNumber).

    exec sp_executesql N '  update [dbo].[People]
     set [FirstName] = @0
     where (([PersonId] = @1) and ([SocialSecurityNumber] = @2))
       ',
    N '  @0 nvarchar(max) ,@1 int,@2 int  ',
    @0 = N '  Rowena  ',
    @1 = 1,
    @2 = 12345678

      如果匹配没有发现(也就是说SocialSecurityNumber已经在数据库中变更了),更新失败抛出OptimisticConcurrencyException异常。

    • 使用Fluent API的开放式并发配置
    public class PersonConfiguration: EntityTypeConfiguration < Person > {
        public PersonConfiguration() {
            Property(p = >p.SocialSecurityNumber).IsConcurrencyToken();
        }
    }

    6.映射到非-Unicode数据库类型

    Convention默认规则 All strings map to Unicode-encoded database types所有的字符串都映射到Unicode数据库类型
    Data Annotation 不可用
    Fluent Entity<T>.Property(t=>t.PropertyName).IsUnicode(boolean)

      默认情况下,Code First会将所有字符串都映射到数据库中的Unicode字符串类型。

      你可以使用IsUnicod方法指定一个字符串是否映射到数据库Unicode字符串类型。下列代码添加到LodgingConfiguation中告诉Code First不要将Owner属性作为Unicode 类型:

    7.对Decimal固定有效位数和小数位数的影响

    Convention默认规则 Decimals are 18, 2
    Data Annotation 不可用
    Fluent Entity<T>.Property(t=>t.PropertyName).HasPrecision(n,n)

      默认情况下,固定有效位数为18,小数位为2

    8.在Code First使用复杂类型

      EF框架从第一版开始就支持复杂类型。复杂类型也可视作值类型(?)可以作为附加属性添加到其他类。复杂类型与实体类型的区别在于复杂类型没有其自己的键。它是依赖于其"宿主"类型跟踪变化 和持久化。

      在People表中如何将Person中的Address包含进来,将Address的属性都映射到People表中?可以直接将所有相关属性都纳入Person类中,见代码3-15:

    public class Person {
        public int PersonId {
            get;
            set;
        }
        public int SocialSecurityNumber {
            get;
            set;
        }
        public string FirstName {
            get;
            set;
        }
        public string LastName {
            get;
            set;
        }
        public string StreetAddress {
            get;
            set;
        }
        public string City {
            get;
            set;
        }
        public string State {
            get;
            set;
        }
        public string ZipCode {
            get;
            set;
        }
    }
    View Code

      但在你的模型中如果使用Address类作为分割类,就可以简化Person类,如代码3-16所示:

    public class Address {
        public int AddressId {
            get;
            set;
        }
        public string StreetAddress {
            get;
            set;
        }
        public string City {
            get;
            set;
        }
        public string State {
            get;
            set;
        }
        public string ZipCode {
            get;
            set;
        }
    }
    public class Person {
        public int PersonId {
            get;
            set;
        }
        public int SocialSecurityNumber {
            get;
            set;
        }
        public string FirstName {
            get;
            set;
        }
        public string LastName {
            get;
            set;
        }
        public Address Address {
            get;
            set;
        }
    }
    View Code

      但是如果这样分割,使用默认规则,会产生一个单独的表:Addresses。而我们目标是让People表中拥有一系列地址字段。如果Adress是一个复杂类型就可以达到这个目的。如果你有其他表中也包含相同的属性,你也可以在那些类中使用Address复杂类型。

    • 定义默认复杂类型

      最方便的方法将Address转化为复杂类型是移除AddressId 属性。现在注释掉它:

      // public int AddressId { get; set; }

      在重新运行程序之前,你需要考虑InsertPerson方法(代码3-7)之前 Address是否存在。因为Address属性没有处理将会成为null值,将会造成SaveChanges抛出DbUpdateException异常。现在可以向代码中插入一个新的Person,并且在Person类中实例化一个新的Address。

    public class Person {
        public Person() {
            Address = new Address();
        }
        //
    }

      除了复杂类型不能有Key以外,Code First中还有两条规则用于检测复杂类型是否满足要求。复杂类型在应用于其他类时只能包含原始属性,只能被用作为非集合类型。换句话说,如果想要Person类中有一个List<Address>或其他Address类型的集合类型属性,Address不能作为复杂类型。

      复杂类型的默认规则

    1. 复杂类型无Key属性

    2. 复杂类型只包含原始属性

    3. 用作其他类的属性时,属性必须是一个单一实例,不能用于集合类型

    • 配置非默认复杂类型

      如果要使用复杂类型,必须要遵循这些规则吗?可能您想要有一个AddressId属性,尽管你知道一个单独的地址实例不会变更,也不需要EF框架对其跟踪。

      如果我们添加AddressId属性重新运行程序,Code First不能推断出你的意图,然后会创建一个单独的Addersses表,并建立与People表的主外键关系。你可以显示地配置复杂类型来修正。

  • 相关阅读:
    [MySQL] LIMIT 分页优化
    [Flutter] 因为不讲这个重点, 全网 flutter 实战视频沦为二流课程
    [Kafka] |FAIL|rdkafka#producer-1 : Receive failed: Disconnected
    [Flutter] lib/main.dart:1: Warning: Interpreting this as package URI, 'package:flutter_app/main.dart'.
    [Flutter] 写第一个 Flutter app,part1 要点
    [Go] 开始试探一门新语言的五点思考
    [转]Android进程间通信
    [转]android ANR产生原因和解决办法
    Android开发之旅(二)服务生命周期和广播接收者生命周期
    为什么要有handler机制?handler机制的原理
  • 原文地址:https://www.cnblogs.com/zhuxiang1633/p/8080679.html
Copyright © 2020-2023  润新知