ASP.NET MVC - Entity Framework

实体关系

关系是某个实体(表)的一条记录对应于另一个实体(表)的一条或多条记录。

一对多关系

单方面的包含关系称为一对多,而一对多和一对一其实是一回事,只是站在不同的角度去看就会有不同的结果,比如有员工表和性向表,站在员工角度去看,一个员工对应了一种性向,而站在性向角度去看,一种性向对应于多名员工。

单向一对一

employee引用了sexual

双向一对一

employee引用了sexual,sexual也引用了employee

多对多

双方面的包含关系,称为多对多。一个艺术家对应于多张专辑,一张专辑对应于多个艺术家。通过链表存储对两张表的引用就可以实现多对多关系。

EF设计器

创建一个CUI项目,右击项目创建ADO实体数据模型

这会在项目中生成一个edmx文件,双击该文件可以打开实体设计器。

创建EF上下文对象

右击实体设计器- 属性,可以配置EF上下文对象

创建实体

右击实体设计器- 新增,可以增加实体

创建属性

右击创建好的实体,可以创建以下类型的属性

以下创建了一个实体,并添加了两个属性

设置实体集的名称

实体就是一条记录,实体集就是多条记录,实体集对应于数据库的表,在.Net项目中,通过EF上下文对象调用实体集可执行Linq查询。单击实体,可以设置实体集的名称,下面将实体集的名称改为了复数。

根据实体生成数据库

右击设计器 - 根据模型生成数据库

选择新建连接

输入数据库名称 - 确定,这会根据数据库连接自动生成数据库。完成后,数据库就自动建好了。

根据数据库生成实体

右击实体设计器 - 从数据库更新模型,这会自动根据数据库创建实体模型。

操作实体

对实体的操作,增删改查都是通过DBContext上下文对象来实现的,它提供了获取实体集(表)的属性。

public void Test( )
{
    DBContext EFContext = new DBContext( );
    //新增
    List<Person> list = new List<Person>
    {
            new Person{ Name="sam" },
            new Person{ Name="leo" }
    };
    EFContext.Persons.AddRange( list ); //or Add
    EFContext.SaveChanges( );

//查询记录
    var result = EFContext.Persons;

//删除
    //需要先查询
    EFContext.Persons.RemoveRange( result ); //or Remove
    EFContext.SaveChanges( );
}

实体关系

实体关系在EF中以导航属性的形式存在

一对多关系

一个部门下有多名员工,以下创建两个实体。

右击主键实体 - 新增 - 关联,可以创建一对多关系。一个部门对应多个员工,Person实体出现了一个导航属性Department和一个标量属性DepartmentId,Department实体出现了一个导航属性Peoples,DepartmentId会变成数据库表字段,而导航属性不会变成表字段,导航属性只在你的项目代码中使用,用以表示实体关系。Person作为外键表引用了Department主键表,所以它有一个DepartmentId指向一个部门的Id。

EFContext.Deparments.Single( ).Peoples; //一个部门有多个员工
EFContext.Persons.Single( ).Deparment; //一个员工隶属于一个部门

多对多关系

一张专辑有多个艺术家,一个艺术家有多张专辑,双方面的包含关系,称为多对多。

以下创建两种多对多关系,第一种是两个实体相互引用,第二种是两个实体对链表的引用。它们在数据库中生成的表没有什么区别,但在EF设计器中的实体会有一些变化。

第一种多对多关系

DBContext EFContext = new DBContext( );

EFContext.Artists.Add( new Artist
{
    ArtistName = "pink floyd",
    Albums = new List<Album> {
    new Album{ AlbumName="The Division Bell" },
    new Album{ AlbumName="Ummagumma" }
}
} );

EFContext.SaveChanges( );

第二种多对多关系

以一个链表实体存储对双方的引用。

DBContext EFContext = new DBContext( );
ICollection<AlbumLinkArtist> list= EFContext.Artists.Single( ).AlbumLinkArtists; //一个艺术家对应多张专辑,专辑id存储在AlbumLinkArtist表中
ICollection<AlbumLinkArtist> list2 = EFContext.Albums.Single( ).AlbumLinkArtists; //一个专辑对于多个艺术家,艺术家id存储在AlbumLinkArtist表中
//增
var artist = new Artist { ArtistName = "Pink Floyd" };
//为同一个艺术家增加两张专辑
AlbumLinkArtist albumLinkArtist1 = new AlbumLinkArtist
{
    Artist = artist,//同一个艺术家
    Album = new Album { AlbumName = "The Division Bell" }
};
AlbumLinkArtist albumLinkArtist2 = new AlbumLinkArtist
{
    Artist = artist,//同一个艺术家
    Album = new Album { AlbumName = "Ummagumma" }
};

EFContext.AlbumLinkArtists.AddRange( new List<AlbumLinkArtist> {
    albumLinkArtist1,
    albumLinkArtist2
} );
EFContext.SaveChanges( );

//查
foreach (var artist in EFContext.Artists)
{
    Console.WriteLine( artist.ArtistName );
    foreach(var AlbumLinkArtist in artist.AlbumLinkArtist)
    {
        Console.WriteLine( AlbumLinkArtist.Album.AlbumName );
    }
}

如果是从数据库生成实体,那么多对多关系的数据库表在生成实体时会有以上两种情况,如果链表只存储了双方的主键id,则生成第一种多对多,如果链表存储了额外的字段,比如Description,则生成第二种多对多实体,也即会多出一个链表实体。无论是哪种多对多实体,表达的都是一个概念,没有区别,只是我们在使用实体时需要加以区分。

自引用关系

在一些表示分类的具有层级关系的表中,表可能会引用自身来表示父节点和子节点,在设计器中可以先创建节点实体,只指定其主键和名称,先不要增加父节点id,如下:

接着创建自引用关系,右击实体 - 关联,如下设置:

将自动生成的引用Id改为ParentId以便于理解,然后将ParentId设为可为null,因为顶级节点没有父节点。

手动插入记录时注意,不需要指定节点的ParentId,由于实体是面向对象的,所以,节点通过其Childs导航属性的Add方法就可以将其它节点作为子节点添加到自身了。

DBContext EFContext = new DBContext( );
Node father = new Node {  NodeName = "书籍" };
Node child1 = new Node {  NodeName = "哲学" };
Node child1HasChild1 = new Node { NodeName = "性经验史" };
Node child1HasChild2 = new Node { NodeName = "存在与虚无" };

//书籍
//    哲学
//      性经验史
//      存在与虚无

child1.Childs.Add( child1HasChild1 );
child1.Childs.Add( child1HasChild2 );
father.Childs.Add( child1 );
EFContext.Nodes.Add( father );
EFContext.SaveChanges( );

深度查询

//先获取根节点
var roots=EFContext.Nodes.Where( node => node.ParentId == null );
StringBuilder builder = new StringBuilder( );
foreach (var node in roots)
{
    ShowNode( node, 0, builder );
}
Console.WriteLine( builder.ToString( ) );
}

public static StringBuilder ShowNode( Node fatherNode, int deep, StringBuilder builder )
{
builder.Append( new string(' ',deep)+ fatherNode.NodeName+"\n" );
foreach (var node in fatherNode.Childs)
{
    ShowNode( node, deep+1, builder );
    deep = fatherNode.Childs.Last( ) == node ? 0 : deep;
}
return builder;
}

Code First模式

新建一个类库项目,命名为MyEF,添加Entity framework的引用,在项目中创建Model目录用来存放领域模型,右击Model目录添加类。

namespace MyEF.Model
{
    public class Person
    {
        public int PersonId { get; set; }
        public string PersonName { get; set; }
    }
}

创建一个自定义的EF上下文,从DBContext派生

using System.Data.Entity;
using MyEF.Model;

namespace MyEF
{
    public class EFContext : DbContext //自定义EF上下文
    {
        public DbSet<Person> Persons { get; set; } //实体模型必须在此处注册,这就是一张表,记录的集合
      
        public EFContext() : base("name=MyEF") //实例构造函数接收数据库连接字符或数据库名称,如果是连接字符,则是config中的ConnectionString=MyEF
        {

}

static EFContext() //静态构造函数可用于指定数据库的创建模式
        {
            //无论怎样,删除同名数据库,再重新创建:
            Database.SetInitializer(new DropCreateDatabaseAlways<EFContext>());
            //默认,参数可为null,当数据库不存在时,自动创建数据库:   
            //Database.SetInitializer ( new CreateDatabaseIfNotExists<EFContext> ( ) ); 
            //如果实体模型发生改变,则先删除同名数据库,再重新创建:
            //Database.SetInitializer ( new DropCreateDatabaseIfModelChanges<EFContext> ( ) );
            // 使数据库保持现状,如果你是后来为已经存在的数据库增加表或表的字段,那么可应用此配置,null表示不做任何改动,但你必须手动Code First增加实体或者为实体增加相应的字段:
            //Database.SetInitializer<EFContext>(null); 或  Database.SetInitializer<EFContext>(new NullDatabaseInitializer<EFContext> );
        }
    }
}

在code first中定义导航属性,导航属性都是类类型且必须修饰为virtual,用以表示实体之间的引用关系。

namespace MyEF.Model
{
    public class Department
    {
        public int DepartmentId { get; set; }
        public string DepartmentName { get; set; }
        public virtual List<Person> Persons { get; set; } //一个部门对应多个员工
    }

public class Person
    {
        public int PersonId { get; set; }
        public string PersonName { get; set; }
        //此处没有显示创建标量的外键DepartmentId,这样,EF会根据导航属性Department在数据库Person表中自动创建一个外键字段
        public virtual Department Department { get; set; } //一个员工对应一个部门
    }
}

再创建一个控制台引用程序,设置app.config,增加一个数据库连接字符串

<configuration>
<connectionStrings>
  <add name="MyEFConn" connectionString="Data Source=.; Initial Catalog=MyEFDB; Integrated Security=True; MultipleActiveResultSets=True; AttachDbFilename=|DataDirectory|MusicStoreD.mdf"
      providerName="System.Data.SqlClient" />
  </connectionStrings>
</configuration>
static void Main(string[] args)
{
    //向数据库插入数据时会自动创建表
   // 默认情况下,数据库文件存储在C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\
    EFContext EFContext = new EFContext();
    Department department = new Department
    {
        DepartmentName = "xxx",
        Persons = new List<Person>
            {
                new Person{ PersonName="sam" },
                new Person{ PersonName="leo" }
            }
    };
    EFContext.Departments.Add(department);
    EFContext.SaveChanges();
}

Code First模式创建实体关系映射

实体间的引用关系是指实体的导航属性与另一个实体关联,下面的方法就是根据导航属性来设置实体间的引用关系。

实体关系的设置分三个步骤

1.创建一个从EntityTypeConfiguration<T>(System.Data.Entity.ModelConfiguration)派生的类型,比如EmployeeConfig.cs文件,然后在这个类型的构造函数中设置实体关系。设置实体关系需要用到以下几个方法,

Has方法:设置单方面的引用关系

HasMany(lambda)
//根据实体间一对多的引用关系为另一方生成可null的外键

HasRequired(lambda)
//根据实体间一对一的引用关系为当前方生成不可null的外键

HasOptional(lambda)
//根据实体间一对一的引用关系为当前方生成可null的外键

由于一对一在多数情况下可以当做一对多,比如一个名员工对应一个部门,但是一个部门也可以对应多个员工,所以一对一和一对多没有区别。
但也有可能出现这种情况:一个员工对应一个住址,但一个住址通常都不会对应多个员工

With方法只能在调用了Has方法后才可以调用,表示进一步设置引用关系

WithMany([lambda])
//无参版:根据实体间一对多的引用关系为双方都生成可null的外键(如果只有单方面的引用则只生成单方面的外键)

WithOptional([lambda])
//无参版:根据实体间一对一的引用关系为另一方生成可null的外键,如果在此方法后调用了HasForeignKey方法,则表示手动指定另一方的外键(假如你没有指定外键表的哪个键作为外键,那么EF会自动根据主键表的主键为外键表增加一个外键字段)

WithRequired([lambda])
//无参版:根据实体间一对一的引用关系为另一方生成不可null的外键,如果在此方法后调用了HasForeignKey方法,则表示手动指定另一方的外键(假如你没有指定外键表的哪个键作为外键,那么EF会自动根据主键表的主键为外键表增加一个外键字段)
 
HasMany可组合三个With方法,而HasRequired与HasOptional只能组合WithMany方法

2.在EF上下文的派生上下文中重写基类的OnModelCreating方法,将从EntityTypeConfiguration<T>派生的类型注册到配置集合中

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Configurations.Add(new EmployeeConfig()).Add(/*……*/); //链式操作注册关系配置
}

一对一的code first

如果实体A引用了实体B,但实体B并不引用实体A,这就是单向的一对一。如果实体A引用了实体B,实体B也引用了实体A,这就是双向的一对一。

单向引用:在实体没有外键的情况下由EF自动创建数据库表的外键

public class Employee
{
    public int EmployeeId { get; set; }
    public string EmployeeName { get; set; }
    public virtual Address Address { get; set; }
}

public class Address
{
    public int AddressId { get; set; }
    public string AddressName { get; set; }
}

//一对一的单向引用,EF自动创建数据库表的外键
public class EmployeeConfig : EntityTypeConfiguration<Employee>
{
    public EmployeeConfig()
    {
        HasKey(employee => employee.EmployeeId);
       HasOptional(employee => employee.Address);
        //等同于 :
        HasOptional(employee => employee.Address).WithMany();
    }
}

单向引用:在实体有外键的情况下由你自己手动指定数据库表的外键

public class Employee
{
    public int EmployeeId { get; set; }
    public string EmployeeName { get; set; }
    public int? AddressId { get; set; } //外键可null时,注意必须设为int?,否则抛错
    public virtual Address Address { get; set; }
}

public class Address
{
    public int AddressId { get; set; }
    public string AddressName { get; set; }
}

//一对一的单向引用,手动指定数据库表的外键
public class EmployeeConfig : EntityTypeConfiguration<Employee>
{
    public EmployeeConfig()
    {
        HasKey(employee => employee.EmployeeId);    
        HasOptional(employee => employee.Address).WithMany().HasForeignKey(employee=>employee.AddressId);
    }
}

最后,将配置类注册到配置集合中就OK了。

public class EFContext : DbContext
{
    public DbSet<Employee> Employees { get; set; }
    public DbSet<Address> Addresss { get; set; }

//……

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new EmployeeConfig()).Add(new AddressConfig());
    }
}

双向引用:在实体没有外键的情况下由EF自动创建数据库表的外键

public class Employee
{
    public int EmployeeId { get; set; }
    public string EmployeeName { get; set; }
    public virtual Address Address { get; set; } //双向引用,则双方实体都必须有导航属性
}

public class Address
{
    public int AddressId { get; set; }
    public string AddressName { get; set; }
    public virtual Employee Employee { get; set; } //双向引用,则双方实体都必须有导航属性
}

//一对一的双向引用,EF自动创建数据库表的外键
public class EmployeeConfig : EntityTypeConfiguration<Employee>
{
    public EmployeeConfig()
    {
        HasKey(employee => employee.EmployeeId);
        //双向引用,双方的外键不可能都是不可null的,如果都是不可null,那么向任何一方插入数据时都必定会抛错
        //所以只可能创建双方外键都可null
        HasOptional(employee => employee.Address).WithMany();
    }
}

双向引用:在实体有外键的情况下由你自己手动指定数据库表的外键

public class Employee
{
    public int EmployeeId { get; set; }
    public string EmployeeName { get; set; }
    public int? AddressId { get; set; } //外键可null时,注意必须设为int?,否则抛错
    public virtual Address Address { get; set; } //双向引用,则双方实体都必须有导航属性
}

public class Address
{
    public int AddressId { get; set; }
    public string AddressName { get; set; }
    public int? EmployeeId { get; set; } //外键可null时,注意必须设为int?,否则抛错
    public virtual Employee Employee { get; set; } //双向引用,则双方实体都必须有导航属性
}

//一对一的双向引用,手动指定数据库表的外键
public class EmployeeConfig : EntityTypeConfiguration<Employee>
{
    public EmployeeConfig()
    {
        HasKey(employee => employee.EmployeeId);
        //手动指定数据库表的外键,这需要在双方的配置类中都显示指定外键才可以
        HasOptional(employee => employee.Address).WithMany().HasForeignKey(employee=>employee.AddressId);
    }
}

public class AddressConfig : EntityTypeConfiguration<Address>
{
    public AddressConfig()
    {
        HasKey(address => address.AddressId);
        //手动指定数据库表的外键,这需要在双方的配置类中都显示指定外键才可以
        HasOptional(address => address.Employee).WithMany().HasForeignKey(address => address.EmployeeId);
    }
}

一对多的code first

在实体没有外键的情况下由EF自动创建数据库表的外键

public class Department
{
    public int DepartmentId { get; set; }
    public string DepartmentName { get; set; }
    public virtual List<Employee> Employees { get; set; }
    public Department()
    {
        Employees = new List<Employee>();
    }
}

public class Employee
{
    public int EmployeeId { get; set; }
    public string EmployeeName { get; set; }
}

//一对多,EF自动创建数据库表的外键
public class DepartmentConfig : EntityTypeConfiguration<Department>
{
    public DepartmentConfig()
    {
        HasKey(department => department.DepartmentId);
        HasMany(department => department.Employees);
        //等同于
        HasMany(department => department.Employees).WithOptional();
    }
}

在实体有外键的情况下由你自己手动指定数据库表的外键

public class Department
{
    public int DepartmentId { get; set; }
    public string DepartmentName { get; set; }
    public virtual List<Employee> Employees { get; set; }
    public Department()
    {
        Employees = new List<Employee>();
    }
}

public class Employee
{
    public int EmployeeId { get; set; }
    public string EmployeeName { get; set; }
    public int? DepartmentId { get; set; }
}

//一对多,手动指定数据库表的外键
public class DepartmentConfig : EntityTypeConfiguration<Department>
{
    public DepartmentConfig()
    {
        HasKey(department => department.DepartmentId);
        HasMany(department => department.Employees).WithOptional().HasForeignKey(employee=>employee.DepartmentId);            
    }
}

多对多的code first

public class Artist
{
    public int ArtistId { get; set; }
    public string ArtistName { get; set; }
    public virtual List<Album> Albums { get; set; }
    public Artist()
    {
        Albums = new List<Album>();
    }
}

public class Album
{
    public int AlbumId { get; set; }
    public string AlbumName { get; set; }
    public virtual List<Artist> Artists { get; set; }
    public Album()
    {
        Artists = new List<Artist>();
    }
}

//多对多,EF自动创建数据库表的外键
public class ArtistConfig : EntityTypeConfiguration<Artist>
{
    public ArtistConfig()
    {
        HasKey(artist => artist.ArtistId);
        //数据库将自动生成一张链表,EF自动创建对两张表的引用外键
        HasMany(artist => artist.Albums).WithMany(album => album.Artists);
    }
}

//多对多,手动指定数据库表的外键
public class ArtistConfig : EntityTypeConfiguration<Artist>
{
    public ArtistConfig()
    {
        HasKey(artist => artist.ArtistId);
        HasMany(artist => artist.Albums).WithMany(album => album.Artists).Map(m => {
            m.ToTable("ArtistAndAlbum");
            m.MapLeftKey("ArtistId");
            m.MapRightKey("AlbumId");
        });
    }
}

自引用的code first

public class Node
{
    public int NodeId { get; set; }
    public string NodeName { get; set; }       
    public int? ParentId { get; set; }
    public virtual Node Parent { get; set; }
    public virtual List<Node> Childs { get; set; }
}
public class NodeConfig : EntityTypeConfiguration<Node>
{
    public NodeConfig()
    {
        HasKey(node => node.NodeId);
        //Node有多个Node
        //当前Node表使用Childs外键引用Node表,外键可null,EF会自动创建一个自动命名的外键
        HasMany(node => node.Childs);
        //手动指定外键
        HasMany(node => node.Childs).WithOptional(node => node.Parent).HasForeignKey(node => node.ParentId);
    }
}

数据库的code first

和先code再生成数据库没有区别,只不过是先有数据库和表,再使用向导完成实体和EF上下文的、映射类的生成。其实数据库的code first应该更灵活,因为你可以随时在数据库更改表字段或增删字段,然后手动更新实体类型的字段即可。如果是使用来自已经创建好的数据库的code first,而数据库表并未定义任何外键关系,那么也可以按照以上方式建立实体在程序中的映射关系,也即如果表没有外键,表与表之间也可以自动关联在一起。如果后来增加了数据库表,那么也只需要在项目中填写一个新的实体即可。

配置实体属性

有两种方式可为属性增加配置,Data Annotations和Fluent API,前者配置方便,后者提供更强大的清洁配置。(如果不喜欢到处贴标签)

1.Data Annotations配置(System.ComponentModel.DataAnnotations)

[Table("Animal")]
//将类映射为Animal表

[Key]
//主键,且种子增量每次+1,即自动增长,增量为1

[Key, DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
//如果主键类型是Guid,则必须配置此特性,否则不会自动生成唯一标识

[System.ComponentModel.DataAnnotations.Schema.ForeignKey]
//设置为外键

[Required]
//不允许空值

[MaxLength(255)]
//最大长度

[MinLength(10)]
//最小长度

[Timestamp]
//并发时间戳,为开放式并发环境配置时间戳。一个实体只能有一个byte [ ] 类型的属性可设置此特性,Sql Server称其为TimeStamp(时间戳),其他数据库称其为RowVersion(行版本)

[ConcurrencyCheck]
//并发非时间戳,当并发冲突发生时,这将为并发提供检查确保不会发生异常。对应的字段类似:public int SocialSecurityNumber { get; set; }

 
[NotMapped]
//不映射到数据库的列,System.ComponentModel.DataAnnotations.Schema

2.Fluent API配置 (System.Data.Entity.ModelConfiguration和System.Data.Entity)

创建一个从EntityTypeConfiguration<T>(System.Data.Entity.ModelConfiguration)派生的类型,然后在这个类型的构造函数中设置实体属性的特性,然后重写自定义的EF上下文从基类继承的OnModelCreating()方法,该方法会在创建表之前将配置信息应用到数据库,所以将每一个实体类属性的配置信息注册在ModelBuilder.Configurations集合中即可。
ToTable(tableNameString )
//设置映射为数据库的表名

HasKey(lambda )
//主键,且种子增量每次+1,即自动增长,增量为1

HasPrecision(n1 , n2 )
//为decimal类型的属性保留有效位数和小数位数,n1为有效位数,n2为小数位数

Property(lambda ).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity )
//如果主键类型是Guid,则必须配置此项,否则不会自动生成唯一标识

Property(lambda ).IsRequired()
//不允许空

Property(lambda ).HasMaxLength()
//字符长度,与数据库表字段的字符长度一样,设为100则生成nvarchar(100)

Property(lambda ).HasColumnType(DBTableColumnType )
//设置字段在数据库表中的列的数据类型,C#有int string datetime类型,但没有数据库表字段的image、text类型,这两个类型可以使用HasColumnType

Property(lambda ).IsRowVersion()
//并发时间戳,为开放式并发环境配置时间戳。一个实体只能有一个byte [ ] 类型的属性可设置此特性,Sql Server称其为TimeStamp(时间戳),其他数据库称其为RowVersion(行版本)

Property(lambda ).IsConcurrencyToken(annotationName , val )
//添加约束
//示例:为多个 字段添加同一个唯一性约束
using System.Data.Entity.Infrastructure.Annotations;
using System.ComponentModel.DataAnnotations.Schema;
Property(lambda ).HasColumnAnnotation(IndexAnnotation.AnnotationName , new IndexAnnotation( new IndexAttribute( "Un_sameRecords" , 1 ) { IsUnique = true } ) );
Property(d => d.TbRightId ).HasColumnAnnotation(IndexAnnotation.AnnotationName , new IndexAnnotation( new IndexAttribute( "Un_sameRecords" , 2 ) { IsUnique = true } ) );

拆分实体到多个表

一个实体拆分成两张表

public class Employee
{
    public int EmployeeId { get; set; }
    public string EmployeeName { get; set; }
    public string EmployeeAddress { get; set; }
}
public class EmployeeConfig : EntityTypeConfiguration<Employee>
{
    public EmployeeConfig()
    {
        HasKey(employee => employee.EmployeeId);          
        Map(m => {
            m.Properties( property => new { property.EmployeeId, property.EmployeeName });
            m.ToTable("Employees");
        })
        .Map(m => {
            m.Properties( property => new { property.EmployeeId, property.EmployeeAddress });
            m.ToTable("EmployeeInfos"); });
    }
}

  

  

待续……

参考资料

EF里一对一、一对多、多对多关系的配置和级联删除

Entity Framework Code First (五)Fluent API - 配置关系

《Entity Framework 6 Recipes》中文翻译系列

//双向引用

ASP.NET MVC - Entity Framework的更多相关文章

  1. 使用ASP.NET MVC+Entity Framework快速搭建系统

    详细资料: http://www.cnblogs.com/dingfangbo/p/5771741.html 学习 ASP.NET MVC 也有一段时间了,打算弄个小程序练练手,做为学习过程中的记录和 ...

  2. Asp.net Mvc Entity Framework Code First 数据库迁移

    1.创建Mvc项目 2.安装Entity Framework 2.1.如下图打开程序包管理器控制台: 2.2.输入命令Install-Package EntityFramework,即可安装Entit ...

  3. ASP.NET MVC+Entity Framework 访问数据库

    Entity Framework 4.1支持代码优先(code first)编程模式:即可以先创建模型类,然后通过配置在EF4.1下动态生成数据库. 下面演示两种情形: 1.代码优先模式下,asp.n ...

  4. ASP.NET MVC+Entity Framework 4.1访问数据库

    Entity Framework 4.1支持代码优先(code first)编程模式:即可以先创建模型类,然后通过配置在EF4.1下动态生成数据库. 下面演示两种情形: 1.代码优先模式下,asp.n ...

  5. 使用ASP.NET MVC+Entity Framework快速搭建博客系统

    学习 ASP.NET MVC 也有一段时间了,打算弄个小程序练练手,做为学习过程中的记录和分享. 首先,得确定需求,木有需求的话,那还搞个毛线呀!嗯……大致思考了一下,终于得出如下需求: 1.能自定义 ...

  6. ASP.NET MVC+Entity Framework code first 迁移

    再来一张,选择 MVC 模版,其他的没选过,不会用 =_=!! 身份验证用个人用户账户,这个是为了偷懒,话说 ASP.NET Identity  还是很给力的,不用白不用 ^_^~ 点击确定之后,会看 ...

  7. ABP 教程文档 1-1 手把手引进门之 ASP.NET Core & Entity Framework Core(官方教程翻译版 版本3.2.5)

    本文是ABP官方文档翻译版,翻译基于 3.2.5 版本 官方文档分四部分 一. 教程文档 二.ABP 框架 三.zero 模块 四.其他(中文翻译资源) 本篇是第一部分的第一篇. 第一部分分三篇 1- ...

  8. ASP.NET Identity + Entity Framework 6 注意

    最近一个项目使用ASP.NET Identity + Entity Framework 6开发,本来一切正常. 某时注意到,更改密码功能程序执行起来没有问题,界面上也报修改密码成功,但实际上密码并没有 ...

  9. MVC & Entity Framework(2)- controller、Models单独DLL

    继上一篇MVC & Entity Framework(1)- 开发环境之后,已经很久没更新了.接下来记录一下怎么把MVC中的controller单独拆为一个类库,然后在web项目中引用.另外, ...

随机推荐

  1. margin塌陷与margin合并(margin),清除浮动

    **1.margin塌陷**问题:垂直方向的父子关系的盒子使用不当会产生margin塌陷.给子级设置margin-top时,他不会相对父级一起动,只有他的margin超过父级的margin时,才会生效 ...

  2. 使用FreeCookies 控制浏览器cookies及修改http响应内容

    FreeCookies 插件安装 :您的计算机需要已经安装Fiddler (如未安装,请至官网下载安装 http://docs.telerik.com/fiddler/configure-fiddle ...

  3. mysql union 与 union all 语法及用法

    1.mysql   union  语法 mysql   union 用于把来自多个select  语句的结果组合到一个结果集合中.语法为: select  column,......from tabl ...

  4. NPOI的基本用法,导出Excel

    void DownloadForAccountIndex(IReadOnlyList<AccountInfoView> list) { NPOI.HSSF.UserModel.HSSFWo ...

  5. react 事件绑定 es5/es6

    // vscode shift + ctrl + v 预览 es 5 写法 无参函数的绑定 first methods 定义函数: handleClick(e) { // e - 事件对象 e.pre ...

  6. 熟悉常用的HDFS操作

    编程实现以下指定功能,并利用Hadoop提供的Shell命令完成相同任务: 在本地Linux文件系统的“/home/hadoop/”目录下创建一个文件txt,里面可以随意输入一些单词. 在本地查看文件 ...

  7. java获取文件行数

    public long getLineNumber(File file) { if (file.exists()) { try { FileReader fileReader = new FileRe ...

  8. 「快速傅里叶变换(FFT)」学习笔记

    FFT即快速傅里叶变换,离散傅里叶变换及其逆变换的快速算法.在OI中用来优化多项式乘法. 本文主要目的是便于自己整理.复习 FFT的算法思路 已知两个多项式的系数表达式,要求其卷积的系数表达式. 先将 ...

  9. python学习日记(常用模块)

    模块概念 什么是模块 常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 但其实import加载的模块分为四个通用类别: 1 使用python编写的代 ...

  10. Tomcat 配置文件 server.xml

    Tomcat隶属于Apache基金会,是开源的轻量级Web应用服务器,使用非常广泛.server.xml是Tomcat中最重要的配置文件,server.xml的每一个元素都对应了Tomcat中的一个组 ...