本节讨论内容主要针对收集了上篇文章大家碰到问题的讨论解决,会持续收集扩充。

  • DbContext加载原值,当前值,数据库值,属性操作,对象复制,对象值复制(VO,DTO->POCO),复杂对象取值
  • DbContext Local Data与AsNoTracking无跟踪查询 如何提高效率
  • DbContext如何关闭延迟加载
  • DbContext如可使用延迟加载
  • DbContext如何控制并发
  • 解除属性映射到数据库中
  • 对象失去或没有被跟踪时处理
  • 多对多关系之扩展字段字段处理
  • 利用模板使模型继承基类
  • 如何对象模型中使用枚举值
  • 创建或使用代理对象

1. DbContext加载原值,当前值,数据库值,属性操作,对象复制,对象值复制(VO,DTO->POCO),复杂对象取值 
(点小图查看大图)

(点小图查看大图)
RoRoWoDBEntities context = new RoRoWoDBEntities();

BlogCategory cate = context.Set<BlogCategory>().Find(3);
BlogArticle arti = cate.BlogArticle.ToList().Find(o => o.ArticleID == 2);
BlogCategory cateOther = context.Set<BlogCategory>().Find(4);
//取当前值
DbPropertyValues currentValues = context.Entry<BlogCategory>(cate).CurrentValues;
//取原值
DbPropertyValues originalValues = context.Entry<BlogCategory>(cate).OriginalValues;
//取数据库值
DbPropertyValues databaseValues = context.Entry<BlogCategory>(cate).GetDatabaseValues();

//从数据库读值覆盖原值
context.Entry<BlogCategory>(cate).OriginalValues.SetValues(databaseValues);
//重新加载对象(并发的时候重新从数据库加载对象,注意给当前值做备份)
context.Entry<BlogCategory>(cate).Reload();
//给当前值赋值
context.Entry<BlogCategory>(cate).CurrentValues.SetValues(currentValues);
//复制其它对象值(这一条很强大,支持任何类型,比如ViewObject,DTO与POCO可以直接映射传值)
context.Entry<BlogCategory>(cate).CurrentValues.SetValues(cateOther);
//单独给每个对象的属性赋值,并且进行标记
context.Entry<BlogCategory>(cate).Property(o => o.ArticleCount).CurrentValue = 10;
context.Entry<BlogCategory>(cate).Property(o => o.ArticleCount).IsModified = true;

//复制对象
BlogCategory newCate =(BlogCategory)context.Entry(cate).GetDatabaseValues().ToObject();
//复杂对象 给子集合某个属性赋值
context.Entry(arti).ComplexProperty(o => o.BlogCategory).Property(c => c.CateName).CurrentValue = "test";
//更改对象状态
context.Entry(arti).State = EntityState.Modified; 2. DbContext Local Data与AsNoTracking无跟踪查询 提高效率  Local Data是通过Load()方法将数据下载到本地,并与Context保持联系,以提高查询效率或者解决批量操作等问题。 
(点小图查看大图)

(点小图查看大图)
RoRoWoDBEntities context = new RoRoWoDBEntities();

DbSet<BlogArticle> set = context.Set<BlogArticle>();
//数据加载到本地(你也可以单独下载某一条数据到本地,Local是下载数据的容器)
set.Load();
//从本地查找指定数据
BlogArticle arti = set.Local.ToList().Find(o => o.ArticleID == 7);
//由于Local Data与context保持联系,所以本地数据的增删改查一样会生效 
//我们可通过重写SaveChanges避免这种问题发生,让Local Data成为一个查询集合
//而所有修改均不更新到数据库存中
set.Remove(arti);
context.SaveChanges(); 重写DbContext SaveChanges方法阻止Local Data数据更新 
(点小图查看大图)

(点小图查看大图)
public partial class RoRoWoDBEntities : DbContext
{
public RoRoWoDBEntities()
: base("name=RoRoWoDBEntities")
{
this.Configuration.LazyLoadingEnabled = false;
}

public override int SaveChanges()
{
//在更新前清除掉Local中的数据
this.Set<BlogArticle>().Local.Clear();
return base.SaveChanges();

.......................
} AsNoTracking无跟踪查询 
(点小图查看大图)

(点小图查看大图)
//实现无跟踪查询提高效率
DbQuery query = set.AsNoTracking();
var result = set.Where(o => o.ArticleID == 7).AsNoTracking().ToList(); 批量操作关闭自动检测提高效率 
(点小图查看大图)

(点小图查看大图)
RoRoWoDBEntities context = new RoRoWoDBEntities();
DbSet<BlogArticle> set = context.Set<BlogArticle>();

List<BlogArticle> list = new List<BlogArticle>();
list.Add(new BlogArticle
{
BlogCategory_CateID = 3,
Content = "小朋友",
Title = "测试001"
});
list.Add(new BlogArticle
{
BlogCategory_CateID = 3,
Content = "大朋友",
Title = "测试002"
});

try
{
//批量操作前 关闭自动检测变化功能
context.Configuration.AutoDetectChangesEnabled = false;

//批量操作
foreach (var blog in list)
{
set.Add(blog);
}
}
finally
{
//开启自动检测变化
context.Configuration.AutoDetectChangesEnabled = true;
context.SaveChanges();
} 3. DbContext如何关闭开启延迟加载 关闭方式 
(点小图查看大图)

(点小图查看大图)
//修改DbContext 配置属性 或者直接设置EDM文件,亦或乾修改tt模板
context.Configuration.LazyLoadingEnabled = false;

//修改POCO 去掉导航属性的virtual修饰 
public partial class BlogArticle
{
....................... 
public virtual BlogCategory BlogCategory { get; set; }
public virtual ICollection<BlogComment> BlogComment { get; set; }
public virtual ICollection<BlogDigg> BlogDigg { get; set; }
} 加载方式 
(点小图查看大图)

(点小图查看大图)
RoRoWoDBEntities context = new RoRoWoDBEntities();
context.Configuration.LazyLoadingEnabled = false;

BlogArticle arti=context.Set<BlogArticle>().Find(7);
//include方式
BlogCategory cate = context.Set<BlogCategory>().Include(o => o.BlogArticle).ToList().Find(c => c.CateID == 3);
//显示加载
context.Entry(cate).Collection(o => o.BlogArticle).Load();
context.Entry(arti).Reference(o => o.BlogCategory).Load(); 4. DbContext如何控制并发 乐观并发的控制 
(点小图查看大图)

(点小图查看大图)
bool saveFailed;
do
{
saveFailed = false;

var blog = context.Set<BlogArticle>().Find(7);
blog.Title = "并发修改名称";

try
{
context.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
saveFailed = true;
//1重新加载已变化的数据
//ex.Entries.Single().Reload();

//2如果页面会刷新 做好当前值备份
var entry = ex.Entries.Single();
DbPropertyValues values = entry.CurrentValues;
entry.Reload();
entry.CurrentValues.SetValues(values);

//3或者给原值重设数据库值
//var entry = ex.Entries.Single();
//entry.OriginalValues.SetValues(entry.GetDatabaseValues());
}

} while (saveFailed); 即使使用Timestamp字段,我们一样也是通过乐观并发控制,然后较验timestamp字段是否一致,或者通过存储过程实现这一过程。 5. 解除属性映射到数据库中 EF 提供了一系列属性用于描述模型

  • KeyAttribute
  • StringLengthAttribute
  • MaxLengthAttribute
  • ConcurrencyCheckAttribute
  • RequiredAttribute
  • TimestampAttribute
  • ComplexTypeAttribute
  • ColumnAttribute
  • TableAttribute
  • InversePropertyAttribute
  • ForeignKeyAttribute
  • DatabaseGeneratedAttribute
  • NotMappedAttribute 
    可以通过NotMappedAttribute标记模型某个属性可以使该属性不必映射到数据库。 
    (点小图查看大图)

    (点小图查看大图)
    public class Unicorn
    {
    public int Id { get; set; }
    [NotMapped]
    public string Name { get; set; }

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

    public int PrincessId { get; set; } // FK for Princess reference
    public virtual Princess Princess { get; set; }
    }

另外我们还可以通过代码的方式,在DbContext的OnModelCreating方法重载中实现,不知道用Code First的人为什么喜欢这种方式处理。DbContext默认是把EDMX文件当成EntityConfiguration加载进来的,和手动处理这些映射关系是一样的。但是手动处理大量的映射关系既不直观,也不容易维护,而EDMX这个模型视图浏览与维护都较之方便啊。

(点小图查看大图)

(点小图查看大图)
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//不映射到数据库中
modelBuilder.Entity<BlogArticle>().Ignore(p => p.Title); 
}  EDMX怎么解除映射还没有找到如何实现,删除表映射EDM验证无法通过,而对象属性又没提供NotMapped 选择。 我觉得如果一个属性不需要映射到数据库时,那这个POCO对象设计肯定是不合理的,可能他是一个合理VO对象,或者是数据库查询视图对象。 6. 对象失去或没有被跟踪时处理 context.Set<BlogArticle>().Attach()  加回上下文中,继续跟踪 7. 多对多关系之扩展字段字段处理 EF 处理多对多关系,是通过中间表主外键关联加载对应的主体表对象,这个中间表是个不存在的业务对象。而中间表如果除了主外键之外还有扩展的字段,就会导致中间表变成一个具体存在的业务对象,让它成为对应主体表的关联导航属性。因此这种中间表设计是不合理,但EF可以应对这种情况。看下图 
(点小图查看大图)

(点小图查看大图)
 Student<-Score(多对多中间表)->Subject  三个对象 由于Score不是一个合理的中间表,导致EF将其映射为一个具体的实体对象成为Student与Subject的导航属性。 而User<-UserProperty(多对多中间表)->Property  UserProperty仅是数据关系的体现,并不是一个具体的实体对象,User与Property是直接导航。 8. 利用模板使模型继承基类 由于我们的纯POCO模型没有基类限制领域,所以在我们的泛型传递POCO的对象给DAL时,就无法限制这个T 是POCO对象呢,还是其它的对象。因此为了将POCO对象与其它业务对象区分开来,可以通过使POCO对象继承一个基类来解决这个问题,当然肯定是模板解决这个问题了。 我们先立一个POCOEntity基类 
(点小图查看大图)

(点小图查看大图)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace EF.Model
{
public class POCOEnity
{
//随便扩展操作属性
//假删除
public bool IsFakeDelete { set; get; }
//脏数据
public bool IsDirty { set; get; } 
}
} 再打DemoDB.tt 模版,找到这段代码(或者直接搜索partial),修改为: 
(点小图查看大图)

(点小图查看大图)
<#=Accessibility.ForType(entity)#> <#=code.SpaceAfter(code.AbstractOption(entity))#>partial class <#=code.Escape(entity)#><#=code.StringBefore(" : ", code.Escape(entity.BaseType))#>:POCOEnity 即在模版生成类结构代码追加其继承POCOEnity基类,修改完成后,点击保存,所有模型类会重新生成,我们看一下生成后的代码 
(点小图查看大图)

(点小图查看大图)
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码是根据模板生成的。
//
// 手动更改此文件可能会导致应用程序中发生异常行为。
// 如果重新生成代码,则将覆盖对此文件的手动更改。
// </auto-generated>
//------------------------------------------------------------------------------

namespace EF.Model
{
using System;
using System.Collections.Generic;

public partial class BlogArticle:POCOEnity
{
public BlogArticle()
{
this.BlogComment = new HashSet<BlogComment>();
this.BlogDigg = new HashSet<BlogDigg>();
}

public int ArticleID { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public string Description { get; set; }
public string ImageUrl { get; set; }
public string Tag { get; set; }
public int Hits { get; set; }
public bool IsTop { get; set; }
public int State { get; set; }
public Nullable<int> UserID { get; set; }
public string UserName { get; set; }
public string UserIP { get; set; }
public Nullable<System.DateTime> CreateTime { get; set; }
public Nullable<System.DateTime> PublishTime { get; set; }
public Nullable<System.DateTime> UpdateTime { get; set; }
public string Note { get; set; }
public int BlogCategory_CateID { get; set; }

public virtual BlogCategory BlogCategory { get; set; }
public virtual ICollection<BlogComment> BlogComment { get; set; }
public virtual ICollection<BlogDigg> BlogDigg { get; set; }
}
} 这个时候我们就可以控制DAL传入的泛型模型参数T的域范围了 public interface IRepository<T> where T : POCOEnity, new()
public abstract class RepositoryBase<T>:IRepository<T> where T :POCOEnity,new() 9. 如何对象模型中使用枚举值 插件: http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=26660 昨晚整了一下,整个VS2010打完补丁后,所有模板都出现2个,程序集还不一致。-_-|||悲剧,看一下微软ADO.NET 团队博客的图 
(点小图查看大图)
 想自己实现的朋友,可以参照ADO.NET TEAM的BLOG。我觉得枚举就是一个转换的过程,不一定非要通过枚举实现,毕竟整个项目用的枚举很多,而这些枚举肯定是存放在一张表里,而不是一个枚举一张表一个对象,若是这样处理起来肯定是给自己增加麻烦。 
10. 创建或使用代理对象 首先开启代理会影响到实体对象的序列化操作(可能无法序列化),但是禁用代理又无法延迟加载导航数据。延迟加载无非是访问这个属性时会自动加载导航属性数据,如果项目需要对象序列化,我们可以禁用代理并闭延迟加载以提高效率,当需要使用导航属性可以使用DbContext.Entity 加载导航数据。 禁用代理对象this.Configuration.ProxyCreationEnabled = false; 当New一个模型时 BlogCategory cate = new BlogCategory(); 则是创建实体对象 而通过DbSet<POCO>.Create() ,则是显示创建代理。 按照MSDN解释,关闭代理就无法跟踪对象的变化了,但实际上我的测试结果是两种情况都可以跟踪到对象的状态变化。不知道MSDN确切指的是什么? 这一节会持续收集问题更新,大家在使用中碰到的问题,可以拿出来一起讨论讨论。

Entity Framework之问题收集的更多相关文章

  1. 《Entity Framework 6 Recipes》中文翻译系列 (21) -----第四章 ASP.NET MVC中使用实体框架之在页面中创建查询和使用ASP.NET URL路由过虑

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 4.2. 构建一个搜索查询 搜索数据是几乎所有应用的一个基本功能.它一般是动态的,因 ...

  2. LINQ之路10:LINQ to SQL 和 Entity Framework(下)

    在本篇中,我们将接着上一篇“LINQ to SQL 和 Entity Framework(上)”的内容,继续使用LINQ to SQL和Entity Framework来实践“解释查询”,学习这些技术 ...

  3. Oracle 与 entity framework 6 的配置,文档

    官方文档: http://docs.oracle.com/cd/E56485_01/win.121/e55744/intro001.htm#ODPNT123 Oracle 对 微软 实体框架 EF6 ...

  4. 使用工具追踪Entity Framework生成的SQL

    学习entity framework期间收集的文章,转自http://www.cnblogs.com/hiteddy/archive/2011/10/01/Difference_among_IQuer ...

  5. Entity Framework技巧系列之十三 - Tip 51 - 55

    提示51. 怎样由任意形式的流中加载EF元数据 在提示45中我展示了怎样在运行时生成一个连接字符串,这相当漂亮. 其问题在于它依赖于元数据文件(.csdl .ssdl .msl)存在于本地磁盘上. 但 ...

  6. 张高兴的 Entity Framework Core 即学即用:(一)创建第一个 EF Core 应用

    写在前面 Entity Framework Core (EF Core) 是 .NET 平台流行的对象关系映射(ORM)框架.虽然 .NET 平台中 ORM 框架有很多,比如 Dapper.NHibe ...

  7. ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第二章:利用模型类创建视图、控制器和数据库

    在这一章中,我们将直接进入项目,并且为产品和分类添加一些基本的模型类.我们将在Entity Framework的代码优先模式下,利用这些模型类创建一个数据库.我们还将学习如何在代码中创建数据库上下文类 ...

  8. Entity Framework Core 1.1 升级通告

    原文地址:https://blogs.msdn.microsoft.com/dotnet/2016/11/16/announcing-entity-framework-core-1-1/ 翻译:杨晓东 ...

  9. Entity Framework Core 实现MySQL 的TimeStamp/RowVersion 并发控制

    将通用的序列号生成器库 从SQL Server迁移到Mysql 遇到的一个问题,就是TimeStamp/RowVersion并发控制类型在非Microsoft SQL Server数据库中的实现.SQ ...

随机推荐

  1. C 基于socket实现简单的文件传输

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAicAAAA5CAIAAABicRxIAAAgAElEQVR4nOy9Z5NVV5om+rzL773POW

  2. delphi AES encrypt

    xe8 ok unit TntLXCryptoUtils; interface function AES128_Encrypt( Value, Password : string ) : string ...

  3. Axis2在Web项目中整合Spring

    一.说明: 上一篇说了Axis2与Web项目的整合(详情 :Axis2与Web项目整合)过程,如果说在Web项目中使用了Spring框架,那么又改如何进行Axis2相关的配置操作呢? 二.Axis2 ...

  4. python's descriptor II

    [python's descriptor II] For instance, a.x has a lookup chain starting with a.__dict__['x'], then ty ...

  5. int* V.S. int[]

    [int* V.S. int[]] 在C++中,int[]有2种形态,一种是指针形态,即使用方法和int*一样,另一种是符号形态,即只是一个编译期的符号(意味着在runtime期,所定义的int[]根 ...

  6. labview 中的一些简写全称

    MAX:Measurement & Automation Explorer 测量自动化管理器 :可用于配置DAQ通道名称,VISA资源名称和IVI逻辑名称. DAQ: Device Data ...

  7. C++视频课程小结(3)

    C++远征之封装篇(上) 章节介绍: 每章小结: 第一章:课程介绍. 按照惯例是章节的总介绍,内容明显多了很多(为了做作业我还要赶进度的说),主要说了:类和对象是本章的主角,然后还有很多配角,像数据成 ...

  8. Codeforces 719 E. Sasha and Array (线段树+矩阵运算)

    题目链接:http://codeforces.com/contest/719/problem/E 题意:操作1将[l, r] + x; 操作2求f[l] + ... + f[r]; 题解:注意矩阵可以 ...

  9. Animation Spinner【项目】

    https://github.com/vjpr/healthkick/blob/master/src/win/healthkick/ucSpinnerCogs.xaml 网上的例子,放在UserCon ...

  10. Tomcat设置自己的项目为默认项目(用IP访问的是自己的项目)

    方法一:将项目拷贝到webapps下,并更名为ROOT; 方法二:在tomcat/conf/service.xml的<host></host>中配置 <Context p ...