`
zxlyecf2
  • 浏览: 133126 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

【配置关系】—Entity Framework实例详解

阅读更多

实体间的关系,简单来说无非就是一对一、一对多、多对多,根据方向性来说又分为双向和单向。Code First在实体关系上有以下约定:

1. 两个实体,如果一个实体包含一个引用属性,另一个实体包含一个集合属性,Code First默认约定它们为一对多关系。 

2. 两个实体,如果只有一个实体包含一个导航属性或一个集合属性,Code First也默认约定它们是一对多关系。 

3. 两个实体分别包含一个集合属性,Code First默认约定它们为多对多关系。 

4. 两个实体分别包含一个引用属性,Code First默认约定它们为一对一关系。 

5. 在一对一关系情况下,需要提供给Code First额外的信息,以确定它们的主从关系。 

6. 在实体中定义一个外键属性,Code First使用属性是否为空来确定关系是必须还是可选。

一、一对一

在Code First中,一对一关系总是需要配置,因为两个实体都包含有一个引用属性,无法确定它们的主从关系。

配置一对一关系常用的方法:

HasRequired ,HasOptional ,WithOptional ,WithRequiredPrincipal,WithRequiredDependent

下面是用到的类:

 public class Person
    {
        public int PersonId { get; set; }
        public int SocialSecurityNumber { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public byte[] RowVersion { get; set; }
        public PersonPhoto Photo { get; set; }
    }

    public class PersonPhoto
    {
        public int PersonId { get; set; }
        public byte[] Photo { get; set; }
        public string Caption { get; set; }
        public Person PhotoOf { get; set; }
    }

 因为Photo是具体人的,所以PersonPhoto使用PersonId作为主键。

下面是一对一关系配置的几种情况:

1.PersonPhoto必须属于一个Person,但是Person不一定有PersonPhoto,这种关系是1:0..1,此种情况下Person是一定存在的,所以它是主从关系主的一方。

   1:  HasRequired(t => t.PhotoOf).WithOptional(t => t.Photo);

   1:  HasOptional(t => t.Photo).WithRequired(t => t.PhotoOf);

2.PersonPhoto必须属于一个Person,Person也必须有PersonPhoto,这种关系式1:1,此种情况下,两个都一定存在,要确定主从关系,需要使用WithRequiredPrincipal或WithRequiredDependent。

   1:  HasRequired(t => t.PhotoOf).WithRequiredDependent(t => t.Photo);

   1:  HasRequired(t => t.Photo).WithRequiredPrincipal(t => t.PhotoOf);

上述两种情况都是真实存在的,不真实存在的就不说了。

下面配置一对一关系贴出Demo:

//配置Person
   public class PersonConfiguration : EntityTypeConfiguration<Person>
   {
       public PersonConfiguration()
       {
           //主键
           HasKey(t => t.PersonId);
           //并发检查
           Property(t => t.SocialSecurityNumber).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None).IsConcurrencyToken();
           //长度50 不为空
           Property(t => t.FirstName).IsRequired().HasMaxLength(50);
           //长度50 不为空
           Property(t => t.LastName).IsRequired().HasMaxLength(50);
           //并发检查
           Property(t => t.RowVersion).IsRowVersion();
           //HasRequired(t => t.Photo).WithRequiredPrincipal(t => t.PhotoOf);
           //HasOptional(t => t.Photo).WithRequired(t => t.PhotoOf);
       }
   }
    
   //配置PersonPhoto
   public class PersonPhotoConfiguration : EntityTypeConfiguration<PersonPhoto>
   {
       public PersonPhotoConfiguration()
       {
           //主键
           HasKey(t => t.PersonId);
           //长度50
           Property(t => t.Caption).HasMaxLength(50);
           //必须从属于Person
           HasRequired(t => t.PhotoOf).WithRequiredDependent(t => t.Photo);
       }
   }
    
  public class BreakAwayContext : DbContext
   {
       public DbSet<Person> People { get; set; }
       public DbSet<PersonPhoto> Photos { get; set; }
    
       protected override void OnModelCreating(DbModelBuilder modelBuilder)
      {
           modelBuilder.Configurations.Add(new PersonConfiguration());
          modelBuilder.Configurations.Add(new PersonPhotoConfiguration());
           base.OnModelCreating(modelBuilder);
       }
   }
    
   public class Initializer : DropCreateDatabaseAlways<BreakAwayContext>
   {
       public Initializer()
       {
       }
    
       //创建数据库时 Seed数据
      protected override void Seed(BreakAwayContext context)
       {
           context.People.Add(new Person()
           {
               FirstName = "E",
               LastName = "F",
               SocialSecurityNumber = 123456,
               Photo = new PersonPhoto()
               {
                   Caption = "这是照片",
                   Photo = new byte[] { }
               }
           });
           context.SaveChanges();
       }

 

二、一对多

下面是用到的类:

 public class Blog
        {
            public Blog()
            {
                Posts = new List<Post>();
            }
     
            public int Id { get; set; }
            public DateTime Creationdate { get; set; }
            public string ShortDescription { get; set; }
            public string Title { get; set; }
            public List<Post> Posts { get; set; }
        }
     
        public class Post
        {
            public int Id { get; set; }
            public string Title { get; set; }
            public string Content { get; set; }
            public DateTime PostedDate { get; set; }
     
            public Nullable<int> BlogId { get; set; }
            public virtual Blog Blog { get; set; }
     
            public int PrimaryAuthorId { get; set; }
            public virtual Author PrimaryAuthor { get; set; }
            public Nullable<int> SecondaryAuthorId { get; set; }
            public virtual Author SecondaryAuthor { get; set; }
        }
     
        public class Author
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public string Email { get; set; }
            //个人简历
            public string Bio { get; set; }
     
            public List<Post> PrimaryAuthorFor { get; set; }
            public List<Post> SecondaryAuthorFor { get; set; }
        }

 配置一对多关系常用的方法有:

HasOptional ,HasRequired ,HasMany

Has方法后面往往跟着With方法

WithOptional ,WithRequired ,WithMany

下面配置一对多的几种情况:

1.Post一定归属于一个Blog,这种关系是1:n。

   1:  HasMany(x => x.Posts).WithRequired(x =>x.Blog)

   1:  HasRequired(x => x.Blog).WithMany(x => x.Posts)

2.Post可以单独存在,不用归属于Blog,这种关系是0..1:n。

   1:  HasMany(x => x.Posts).WithOptional(x => x.Blog)

   1:  HasOptional(x => x.Blog).WithMany(x => x.Posts)

设置外键

外键的默认约定:

[Target Type Key Name], [Target Type Name] + [Target Type Key Name], or [Navigation 

Property Name] + [Target Type Key Name]

本例中,匹配的是[Target Type Name] + [Target Type Key Name],目标类型是Blog,目标类型主键是Id,加起来就是BlogId。下面使用Fluent API显示设置外键:

   1:  HasMany(x => x.Posts).WithOptional(x => x.Blog).HasForeignKey(x => x.BlogId)

设置级联删除

   1:  HasMany(x => x.Posts).WithOptional(x => x.Blog).HasForeignKey(x => x.BlogId).WillCascadeOnDelete();

反转属性

在Post实体中,有两个属性:PrimaryAuthor和SecondaryAuthor,第一作者和第二作者。在Author中有两个集合属性,Code First默认不能确定哪个集合属性和Post中的导航属性相匹配。使用Fluent API配置反转属性,如下:

   1:  HasRequired(t => t.PrimaryAuthor).WithMany(t => t.PrimaryAuthorFor);

   2:  HasOptional(t => t.SecondaryAuthor).WithMany(t => t.SecondaryAuthorFor);

下面是配置一对多关系的Demo

public class BlogConfiguratioin : EntityTypeConfiguration<Blog>
 {
     public BlogConfiguratioin()
     {
         ToTable("Blogs");
         HasKey(t => t.Id);
         Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
         Property(t => t.Title).IsRequired().HasMaxLength(250);
         Property(t => t.Creationdate).HasColumnName("CreationDate").IsRequired();
         Property(t => t.ShortDescription).HasColumnType("Text").IsMaxLength().IsOptional().HasColumnName("Description");
         //配置Blog和Post的一对多关系,Blog对Post是可选的,外键BlogId,并设置为级联删除
         HasMany(t => t.Posts).WithOptional(t => t.Blog).HasForeignKey(t => t.BlogId).WillCascadeOnDelete();
     }
 }
  
 public class PostConfiguration : EntityTypeConfiguration<Post>
 {
     public PostConfiguration()
     {
         ToTable("Posts");
         HasKey(t => t.Id);
         Property(t => t.Id).HasColumnName("PostId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
         Property(t => t.Content).HasColumnName("Body").IsMaxLength();
         Property(t => t.PostedDate).HasColumnName("PostedDate");
         Property(t => t.Title).HasColumnName("Title").IsMaxLength();
         //配置反转属性,集合属性PrimaryAuthorFor匹配PrimaryAuthor
         HasRequired(t => t.PrimaryAuthor).WithMany(t => t.PrimaryAuthorFor);
         //配置反转属性,集合属性SecondaryAuthorFor匹配SecondaryAuthor
         HasOptional(t => t.SecondaryAuthor).WithMany(t => t.SecondaryAuthorFor);
     }
 }
  
 public class AuthorConfiguration : EntityTypeConfiguration<Author>
 {
     public AuthorConfiguration()
     {
         ToTable("Authors");
         HasKey(t => t.Id).Property(t => t.Id).HasColumnName("AuthorId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
         Property(t => t.Name).IsRequired().HasMaxLength(50);
         Property(t => t.Email).IsRequired().HasMaxLength(50);
         Property(t => t.Bio).HasMaxLength(1000);
     }
 }
  
 public class BreakAwayContext : DbContext
 {
     public DbSet<Blog> Blogs { get; set; }
     public DbSet<Post> Posts { get; set; }
     public DbSet<Author> Authors { get; set; }
  
     protected override void OnModelCreating(DbModelBuilder modelBuilder)
     {
         modelBuilder.Configurations.Add(new BlogConfiguratioin());
         modelBuilder.Configurations.Add(new PostConfiguration());
         modelBuilder.Configurations.Add(new AuthorConfiguration());
         base.OnModelCreating(modelBuilder);
     }
 }
  
 public class Initializer : DropCreateDatabaseAlways<BreakAwayContext>
 {
     public Initializer()
     {
     }
  
     protected override void Seed(BreakAwayContext context)
     {
         var primaryAuthor = new Author()
         {
             Name = "张三",
             Email = "zhangsan@126.com",
             Bio = "张三的简历"
         };
         var secondaryAuthor = new Author()
         {
             Name = "李四",
             Email = "lisi@126.com",
             Bio = "李四的简历"
         };
         var blog = new Blog()
         {
             Title = "EF",
             ShortDescription = "关于EF的博客",
             Creationdate = DateTime.Now
         };
         blog.Posts.Add(new Post()
         {
             Title = "配置关系",
             PostedDate = DateTime.Now,
             Content = "这是Post的内容",
             PrimaryAuthor = primaryAuthor,
             SecondaryAuthor = secondaryAuthor
         });
         context.Blogs.Add(blog);
         context.SaveChanges();
     }

 

三、多对多

下面是配置多对多关系用到的类,跟一对多差不多,只不过Post和Author的关系变成多对多的了。

public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public DateTime PostedDate { get; set; }

    public virtual List<Author> Authors { get; set; }
}

public class Author
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    //个人简历
    public string Bio { get; set; }

    public virtual List<Post> Posts { get; set; }
}

 一篇文章有多个作者,一个作者著有多篇文章。

配置多对多关系使用HasMany和WithMany方法,可以使用Map配置生成关联表的名字。

下面是配置多对多关系的Demo:

public class PostConfiguration : EntityTypeConfiguration<Post>
{
    public PostConfiguration()
    {
        ToTable("Posts");
        HasKey(t => t.Id);
        Property(t => t.Id).HasColumnName("PostId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        Property(t => t.Content).HasColumnName("Body").IsMaxLength();
        Property(t => t.PostedDate).HasColumnName("PostedDate");
        Property(t => t.Title).HasColumnName("Title").IsMaxLength();
        //配置多对多关系 ToTable 配置生成的关联表名字 MapLeftKey默认表示调用HasMany的实体的主键
        //本例中如果不使用MapLeftKey默认生成Post_Id
        HasMany(t => t.Authors).WithMany(t => t.Posts).Map(m =>
            {
                m.ToTable("PostAuthor");
                m.MapLeftKey("PostId");
                m.MapRightKey("AuthorId");
            });
    }
}
 
public class AuthorConfiguration : EntityTypeConfiguration<Author>
{
    public AuthorConfiguration()
    {
        ToTable("Authors");
        HasKey(t => t.Id);
        Property(t => t.Id).HasColumnName("AuthorId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        Property(t => t.Bio).HasColumnType("Text").IsMaxLength();
        Property(t => t.Email).HasMaxLength(100).IsRequired();
        Property(t => t.Name).HasMaxLength(100).IsRequired();
    }
}
 
public class TestContext : DbContext
{
    public DbSet<Post> Posts { get; set; }
    public DbSet<Author> Authors { get; set; }
 
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new PostConfiguration());
        modelBuilder.Configurations.Add(new AuthorConfiguration());
        base.OnModelCreating(modelBuilder);
    }
}
 
public class Initializer : DropCreateDatabaseAlways<TestContext>
{
    protected override void Seed(TestContext context)
    {
        var post = new Post()
        {
            Title = "Post1",
            Content = "Content1",
            PostedDate = DateTime.Now
        };
        var author = new Author()
        {
            Name = "张三",
            Email = "zhangsan@126.com",
            Bio = "张三的简历"
        };
        var author1 = new Author()
        {
            Name = "李四",
            Email = "lisi@126.com",
            Bio = "李四的简历"
        };
        var author2 = new Author()
        {
            Name = "王五",
            Email = "wangwu@126.com",
            Bio = "王五的简历"
        };
        post.Authors.Add(author);
        post.Authors.Add(author1);
        context.Posts.Add(post);
        post = new Post()
        {
            Title = "Post2",
            Content = "Content2",
            PostedDate = DateTime.Now
        };
        post.Authors.Add(author);
        post.Authors.Add(author2);
        context.Posts.Add(post);
        context.SaveChanges();
    }
}

 

分享到:
评论

相关推荐

    MVC3 EntityFramework CRUD

    **MVC3 Entity Framework CRUD详解** 在Web开发领域,ASP.NET MVC框架以其清晰的模型-视图-控制器(MVC)架构模式而受到广泛的欢迎。MVC3是该框架的一个版本,提供了更好的性能和更多的特性。同时,Entity ...

    ADO.NET Entityframework 書籍

    #### 标题理解:“ADO.NET Entityframework 書籍” 本书籍主要介绍了ADO.NET与Entity Framework的核心概念、技术细节及其在现代软件开发中的应用。其中特别强调了DbContext作为Entity Framework的一个关键组件,在...

    entity framework

    **Entity Framework详解** - **EDM (Entity Data Model)**:是EF的核心,它定义了应用程序和数据库之间的数据模型。EDM分为三个主要部分: - **CSDL (Conceptual Schema Definition Language)**:描述应用程序的...

    Entity Framework技术系列之7:LINQ to Entities.pdf

    LINQ to Entities是LINQ技术在Entity Framework中的具体实现,它提供了一种使用LINQ查询Entity Framework实体数据模型的方法。LINQ to Entities可以生成eSQL(Entity SQL),并支持使用LINQ语法对实体框架服务层进行...

    利用ADO.net entity framework+Linq实现的学习源代码

    **Entity Framework详解** Entity Framework通过创建模型类和数据库之间的映射,简化了数据库操作。开发者可以操作对象而不是直接执行SQL,从而降低了数据库相关的复杂性。它支持Code First、Model First和Database...

    详解如何在ASP.NET Core中应用Entity Framework

    2. `Install-Package Microsoft.EntityFrameworkCore.Tools –Pre` - 安装预览版本的Entity Framework Core工具,用于数据库上下文生成。 3. `Install-Package Microsoft.EntityFrameworkCore.SqlServer.Design` - ...

    基于EntityFrameworkCore和Lucene.NET的全文检索搜索引擎源码

    【EntityFrameworkCore详解】 EntityFrameworkCore(简称EF Core)是微软开发的一个轻量级、高性能的ORM框架,它是Entity Framework的最新版本。ORM(对象关系映射)允许开发者使用面向对象的方式来操作数据库,...

    Entity Framework 4 in Action

    《Entity Framework 4 in Action》是一本详尽而实用的指南,它不仅深入浅出地讲解了实体框架的基本概念和技术细节,还提供了丰富的实例帮助读者掌握实际应用技巧。对于希望在.NET平台上开发高性能数据驱动应用的...

    Programming Entity Framework Code First

    Entity Framework是微软提供的一种用于.NET应用程序的数据访问技术,它支持多种数据库平台,并且具有ORM(对象关系映射)功能,能够简化数据访问层的开发工作。 **描述:“Julia Lerman与Rowan Miller的关于Code ...

    Entity Framework技术系列之1:数据访问技术概述

    从最初的ADO.NET,到后来出现的各种简化封装和技术革新,如SqlHelper、DAAB(Data Access Application Block)、LINQ,直至现在广泛推荐使用的Entity Framework,这一路见证了.NET平台上数据访问技术的发展历程。...

    MysqlEntityFramework的Demo

    《MySQL Entity Framework实战示例详解》 MySQL Entity Framework(简称EF)是.NET框架下的一款ORM(对象关系映射)工具,它允许开发人员使用面向对象的编程方式来操作数据库,而无需关注底层的SQL语句。本篇将通过...

    Programming Entity Framework, 实体架构编程, Julia Lerman

    ### 实体框架编程(Entity Framework)详解 #### 一、实体框架编程简介 实体框架(Entity Framework,简称EF)是一种由微软开发的数据访问技术,它为.NET开发人员提供了一种新的方式来处理关系型数据库中的数据。...

    c#程序100实例详解

    这些实例可能涉及GUI编程(如Windows Forms或WPF)、数据库交互(ADO.NET或Entity Framework)、网络编程、XML处理、文件I/O操作等。通过解决这些实际问题,读者可以提升编程技能,积累实战经验。 高级主题方面,C#...

    springmvc与mybatis集成配置实例详解

    &lt;bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"&gt; &lt;!-- 其他配置 --&gt; &lt;property name="basePackage" value="com.example.mapper" /&gt; &lt;!-- ...

    MVP ASP.NET实例

    Entity Framework是微软提供的一种对象关系映射(ORM)框架,它允许开发者使用面向对象的编程方式来操作数据库。在MVP模式中,Entity Framework可以作为数据访问层,简化数据库交互。开发者可以创建实体类来表示...

Global site tag (gtag.js) - Google Analytics