Linq To Entity经验:如何解决按需所取

LINQ to Entity LINQ toSQL和 Entity Framework 的区别 LINQ to SQL和Entity Framework都是一种包含LINQ功能的对象关系映射(ORM)技术。他们之间的本质区别在于Entity Framework对数据库架构和查询的类型实行了更好的解耦。使用Entity Framework,查询的对象不再是完全对应数据库架构的C#类,而是更高层的抽象:Entity Data ... 阅读详情

来自:http://www.cnblogs.com/ASPNET2008/archive/2013/03/27/2985796.html

已经有一阵没有写博客了,并不是不想写,只不过最近的项目实在事太多没时间总结,最近项目客户提到了网站性能问题,这让我不得不反思自己在项目中应EntityFramework是不是有些地方应该可以优化的。
   
    常见问题:

    1:EntityFramework如何在DbModel(数据库模型)与DoaminModel(领域模型)之间进行DTO?

       什么是DTO,就是数据转换,我们从数据库中查询出来的是数据库模型对象,和数据库表结构是对应上的,但领域模型是给业务功能模块使用的,字段名称等各方面都有可能不相同。

       方法一:自己编写反射方法,进行属性复制;下面是部分示例代码         

复制代码
 public T ReturnModel<T, TS>(TS c) where T : new()
        {
            var result = new T();
            var properties = typeof(T).GetProperties();
            var sProperties = typeof(TS).GetProperties();
            foreach (var propertyInfo in properties)
            {
                foreach (var spropertyInfo in sProperties)
                {
                    if (propertyInfo.Name.Equals(spropertyInfo.Name))
                    {
                        if (propertyInfo.PropertyType.FullName != null && propertyInfo.PropertyType.FullName.Equals(spropertyInfo.PropertyType.FullName))
                        {
                            propertyInfo.SetValue(result, spropertyInfo.GetValue(c, null), null);
                        }
复制代码

 

       方法二:利用一些自动化的工具,比如AutoMapper,这个东东我就不贴代码了,是个开源的,下载源码看下就行。
       问题:  

          如果采用以上两个方法进行数据库与领域模型之间DTO,那么默认情况下,EntityFramework会将关联到的表的所有字段取到客户端,不管你用还是不用,前提是已经关闭了EntityFramework延迟加载属性。


    2:EntityFramework能否只返回我们所需要的字段?
       既然我们需要DTO,又有我们不想看到的select * 的效果,那么如何按需所取呢?
       答案是肯定的,借用我同事的一句话就是:如果EntityFramework这点事也解决不了微软也不好意思拿出来呀。
   
       常见解决方案:根据不同的方法编写不同的Select,比如:
       

复制代码
var dataList = dao.Query(newfilter).Select(
                   p => new ObjectModel.Specialty
                   {
                       Id = p.Specialty.Id,
                       Name = p.Specialty.Name
                   }
                   ).Distinct().ToList();
复制代码

               
       这种方案并没有什么不好,只不过需要根据自己的需求编写不同的数据库查询方法。
      
       最近看见一老外写了篇不错的文章(停止在数据库访问层中运用AutoMapper),正好符合我的需求,它的主意就是将自己需要的数据整合在一个领域模型中,程序员不再需要编写不同的后台查询,只需要按需求定义好领域模型就可以了。

      http://www.devtrends.co.uk/blog/stop-using-automapper-in-your-data-access-code
       
       比如有如下表结构:
      
       需求:查询所有学生信息,并且显示每个学生的老师姓名,老师类型信息。
      
       也许我们需要这样写:
       

复制代码
var dataList = dao.Query(newfilter).Select(
                   p => new ObjectModel.Specialty
                   {
                       
                       StudentName = p.Name,
                       TeacherName=p.Teacher.Name,
                       TeacherTypeName=p.Teacher.TeacherType.Name
                   }
                   ).ToList();
复制代码

 

       为何不这样写:
       首先我们定义领域模型:
       

复制代码
public class StudentSummary
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Teacher_Name { get; set; }
        public string Teacher_TeacherType_Name { get; set; }
       
    }
复制代码

 

        程序调用: 

 var students = context.Students.Project().To<StudentSummary>();


       多么简洁!来看看它的实现原理:利用反射得到数据库模型以及领域模型的属性信息,然后我们利用按照一定规则定义的领域模型进行动态表达式树(主要是Select表达式树的构建)的构建,比如上面的StudentSummary中的Teacher_Name,为什么中间有一个"_",其实这是我自己定义的一种规则,用以区分是简单属性还是复杂属性,说明下这里的简单属性就是指数据类型是int,string这一流的,复杂属性就是指Teacher这种Class型的。
   
      老外的项目是利用大写字母来区分的,定义成TeacherName,这将会分成两个词:Teacher,以及Name,那么他认为这个Teacher是一个复杂属性,最后面的Name是一个简单属性。而我在些基础上多增加了一层支持,比如我们访问学生的老师的类型:student.Teacher.TeacherType.Name,如果.net定义属性能使用"."那么我会在Student上定义这样的属性:Teacher.TeacherType.Name,但不允许,我只能用"_"代替,尽管看起来有些别扭,但好在解决了我的问题。

     下面是我按自己的需求修改过的扩展代码:

View Code
复制代码
public static class QueryableExtensions
    {
        public static ProjectionExpression<TSource> Project<TSource>(this IQueryable<TSource> source)
        {
            return new ProjectionExpression<TSource>(source);
        }
    }

    public class ProjectionExpression<TSource>
    {
        private static readonly Dictionary<string, Expression> ExpressionCache = new Dictionary<string, Expression>();

        private readonly IQueryable<TSource> _source;

        public ProjectionExpression(IQueryable<TSource> source)
        {
            _source = source;
        }

        public IQueryable<TDest> To<TDest>()
        {
            var queryExpression = GetCachedExpression<TDest>() ?? BuildExpression<TDest>();

            return _source.Select(queryExpression);
        }

        private static Expression<Func<TSource, TDest>> GetCachedExpression<TDest>()
        {
            var key = GetCacheKey<TDest>();

            return ExpressionCache.ContainsKey(key) ? ExpressionCache[key] as Expression<Func<TSource, TDest>> : null;
        }

        private static Expression<Func<TSource, TDest>> BuildExpression<TDest>()
        {
            var sourceProperties = typeof(TSource).GetProperties();
            var destinationProperties = typeof(TDest).GetProperties().Where(dest => dest.CanWrite);
            var parameterExpression = Expression.Parameter(typeof(TSource), "src");

            var bindings = destinationProperties
                                .Select(destinationProperty => BuildBinding(parameterExpression, destinationProperty, sourceProperties))
                                .Where(binding => binding != null);

            var expression = Expression.Lambda<Func<TSource, TDest>>(Expression.MemberInit(Expression.New(typeof(TDest)), bindings), parameterExpression);

            var key = GetCacheKey<TDest>();

            ExpressionCache.Add(key, expression);

            return expression;
        }

        private static MemberAssignment BuildBinding(Expression parameterExpression, MemberInfo destinationProperty, IEnumerable<PropertyInfo> sourceProperties)
        {
            var sourceProperty = sourceProperties.FirstOrDefault(src => src.Name == destinationProperty.Name);

            if (sourceProperty != null)
            {
                return Expression.Bind(destinationProperty, Expression.Property(parameterExpression, sourceProperty));
            }
            var propertyNames = SplitTableName(destinationProperty.Name);

            if (propertyNames.Length == 2)
            {
                sourceProperty = sourceProperties.FirstOrDefault(src => src.Name == propertyNames[0]);
                if (sourceProperty != null)
                {
                    var sourceChildProperty = sourceProperty.PropertyType.GetProperties().FirstOrDefault(src => src.Name == propertyNames[1]);

                    if (sourceChildProperty != null)
                    {
                        return Expression.Bind(destinationProperty, Expression.Property(Expression.Property(parameterExpression, sourceProperty), sourceChildProperty));
                    }
                }
            }
            else if (propertyNames.Length == 3)
            {
                var firstSourceProperty = sourceProperties.FirstOrDefault(src => src.Name == propertyNames[0]);
                if (null == firstSourceProperty) return null;
                var secondSourceProperty = firstSourceProperty.PropertyType.GetProperties().FirstOrDefault(src => src.Name == propertyNames[1]);
                if (null == secondSourceProperty) return null;

                var sourceChildProperty = secondSourceProperty.PropertyType.GetProperties().FirstOrDefault(src => src.Name == propertyNames[2]);

                if (sourceChildProperty != null)
                {
                    var secondProp=Expression.Property( parameterExpression ,firstSourceProperty );
                    var firstProp = Expression.Property(secondProp, secondSourceProperty);
                    var resultProp=Expression.Property( firstProp , sourceChildProperty);
                    return Expression.Bind(destinationProperty, resultProp);
                }
            }
            else if (propertyNames.Length == 1)
            {
                return null;
            }
            else
            {
                throw new NotSupportedException("do not suports this kind of operation");
            }
            return null;
        }

        private static string GetCacheKey<TDest>()
        {
            return string.Concat(typeof(TSource).FullName, typeof(TDest).FullName);
        }
        private static string[] SplitTableName(string input)
        {
            return input.Trim().Split('_');
        }
    }
复制代码

  
     EntiryFrameWork还是很强大的,对付一般小型项目基本不会存在性能问题,除非您的小项目会有大数据量的情况,大多数情况都是使用不当引起的性能问题。


Linq to Entity动态查询与匿名类型实战 是命名空间下的一个类,它为IQueryable接口提供了一组扩展方法,允许使用字符串表达式代替传统的 Lambda 表达式进行查询。这些方法包括:例如:与传统的 LINQ 查询相比,这种方式允许在运行时构建查询条件,而不是在编译时固定逻辑。除了返回匿名类型,也可以通过自定义类来接收查询结果,提升数据结构的可维护性。set;set;set;参数说明:UserInfo是一个自定义类型,用于接收查询结果。表示最终投影结果将映射到该类型。 阅读详情

相关推荐

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

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

链表之单链表的实现

链表的特点: 1:空间上按需所取; 2:物理空间不连续 链表在物理空间上的不连续,方便增删查改; 单链表包括存储的数据和指向下一个节点的指针 链表基础结构由结构体实现 typedef int LIST;//方便更改类型 typedef struct SList { LIST data; struct SList* next; }SList; 主要有四个功能: 增删查改; 1:增加又可分为...

qq_64128135的博客 376

linq to entity

linq连接数据库,linq学习例子,linq to entiry,比ADO.NET要简单、省时、高效。

按需所取、弹性分配的云计算

云计算是一种按使用量付费的模式,这种模式提供可用的、便捷的、按需的网络访问, 进入可配置的计算资源共享池(资源包括网络、服务器、存储、应用软件,服务),这些资源能够被快速提供,只需投入很少的管理工作,或与服务供应商进行很少的交互。其实,云计算的目标很明确,寄希望通过这种新技术,通过管理、调度与整合分布在网络上的各种资源,以统一的界面为大量用户提供服务,用...

weixin_34216036的博客 1182

Linq to sql 和 Linq to Entity 高级查询

实现linq多个查询条件连接功能(支持linq to sql 和linq to entity)。 按多个指定属性排序功能。 不同参数的lamdba表达式条件间的转换功能。

深入解析ACS SPiiPlus运动控制器的托管API架构与实战应用

本文深入解析了ACS SPiiPlus运动控制器的托管API架构,详细介绍了其核心模块、设计哲学与实战应用。通过C#/.NET封装的托管接口,开发者能够高效实现多轴协同运动控制、EtherCAT总线集成以及事件驱动的异步编程,显著提升高精度工业自动化设备的开发效率与系统稳定性。

jwt8token的博客 861

【转】Entity Framework技术系列之7:LINQ to Entities

前言 LINQ(Language Integrated Query,语言集成查询)是一组用于C#和VB.NET语言的扩展,它允许编写C#或者VB.NET代码,以与查询数据库相同的方式操作内存数据。 LINQ提Entity Framework技术系列之7:LINQ to Entities供了丰富的类似SQL的查询语法,功能强大且容易上手。下图汇总展示了LINQ技术的官方实现集合: ...

168

【vue看板】

大屏看板提示:以下是本篇文章正文内容,下面案例可供参考提示:这里对文章进行总结:代码量较多,看板中的。

weixin_46223284的博客 2771

LINQ TO SQL和Entity Framework 的关系 你了解多少?

1. LINQ TO SQL 和EF 特点: LINQ TO SQL和Entity Framework都是一种包含LINQ功能的ORM 也就是所谓的关系对象的映射。其中包括的有DBFrist Code Frist ModeL Frist 三种中方式 来进行和数据库之间的访问。只是形式不同而已本质没有什么区别。都是ORM 之间的转化。最终都是来进行访问底层的数据库的对象和服务。 简单来说LINQ是为了满足不知道怎么操作数据库的程序员开发设计的,LinQ 可以让他们以一种面向数据对象的方式来思考,及

极客神殿 595

从“氛围编程“到“智能体工程“:AI编程范式的认知跃迁与工程实践

摘要: 2026年,ClaudeCode负责人鲍里斯·切尔尼提出用“智能体工程”(Agent Engineering)替代流行的“氛围编程”(Vibe Coding),认为后者过于主观,无法体现AI编程的系统化与工程化本质。智能体工程强调记忆系统、工具编排、任务分解、可观测性等核心技术,将AI编程从“玄学辅助”升级为可度量、可规模化的工程学科。本文通过对比术语差异、构建知识体系,并结合代码实例(如带记忆系统的代码生成Agent和可观测性系统),展示了智能体工程的实际应用。行业案例(如ClaudeCode的并

yyq916的博客 1060

echarts实现3D地图——map3D

【代码】echarts实现3D地图——map3D。

xiaoququ的博客 7316

Linq to Entity 增,删,改,查 语句

一、增 public void Insert(ExamineeDto item) { using (var ctx = new PersonnelExamEntities()) { var newItem = new Ex_Examinee {

Java_c# 3666

JMeter脚本录制-快速上手篇

有的项目应用场景下,压测时,需要考虑带宽因素,压测不只是压测接口,静态资源也要一起压测。一般来说,静态资源比较多,如果一个个手工去写请求,是比较繁琐的,此时,可以使用Jmeter的脚本录制功能。 步骤1,创建脚本录制模版。 JMeter菜单:文件>模版,下拉选择到Recording,点击“Create”按钮; 填写录制参数: hostToRecord:填写要录制的主机域名,例如,我们这里填入:www.baidu.com schemeToRecord:填写要录制的模式,例如,htt...

软件测试大叔 5733

关于linq to entity中toString()的使用

今天在工作中遇到一个问题,写了一个方法: public virtual List GetRegistCourse(string accountId) { if (string.IsNullOrEmpty(accountId)) { return null; } List list =

幸运的猪 1557

ABAP代码使用OAuth2.0 Client Credential调用外部API

ABAP-OAuth2.0-调用外部API

m0_74015269的博客 1951

【WRF数据准备】气象驱动数据-ERA5再分析数据(Copernicus)

【WRF数据准备】气象驱动数据-ERA5再分析数据

WW、forever的博客 5521

MediaGo 设置页面参数全解:从基础/浏览器/下载配置到源码级实现机制

本文基于 MediaGo 官方文档《使用方法》(docs/jp/documents.md)整理并扩充,逐条解析设置页三大区块(基础设置、浏览器设置、下载设置)中每个参数的含义与影响,并结合开源仓库中的前端组件(`apps/ui/src/pages/setting-page/`)、公共类型定义(`packages/common/src/types/index.ts`)与 Go 核心配置实现(`app

gitblog_00655的博客 1106

微信开发 - 最新第三方网站接入微信登录、微信支付时,本地 redirect_uri 参数错误导致无法调试的解决方案(微信开放平台)完美解决每次都需要部署到线上测试,在本地使用本地 ip 就能轻松调试

redirect_uri参数错误,微信第三方登录,没有服务器时的测试方法,微信开放平台的回调域名怎么设置为本地域名IP,微信登录微信支付每次调试都需要放到服务器上怎么办,微信登录支付业务在本地调试不了怎么办,在本地怎么测试微信支付和登录,微信第三方登陆本地测试,怎么在本地进行测试,微信回调域怎么设置为本地IP,微信扫码登录redirect_uri参数错误,微信开放平台,微信开放平台开发的第三方登录和支付,vue2,nuxt2,vue3,nuxt3,uniapp,微信开放平台,公众号,微信支付,微信登录授权,

🏆 前端领域优质创作者 8790

Entity Framework 和 LINQ To SQL的区别

综述 LINQ是一种语言集成查询,它包含了LINQ to SQL,LINQ to Objects,LINQ to XML,LINQ to Entities(Entity Framework两种查询方式之一,另外一种叫做Entity SQL)。 Entity Framework 是一种ORM (Object Relational Mapping)框架,把关系型数据转换成对象的一种框架。 LINQ to SQL是Linq最初提供的一种访问数据的方式,它允许你从SQL Server数据库获取数据。 LINQ to

极客神殿 1081

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

LINQ TO SQL和Entity Framework 的关系

1. LINQ TO SQL 和EF 特点: LINQ TO SQL和Entity Framework都是一种包含LINQ功能的ORM 也就是所谓的关系对象的映射。其中包括的有DBFrist Code Frist ModeL Frist 三种中方式 来进行和数据库之间的访问。只是形式不同而已本质没有什么区别。都是ORM 之间的转化。最终都是来进行访问底层的数据库的对象 和服务。...

xulong5000的专栏 334

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

LINQ之路 9:LINQ to SQL 和 Entity Framework(上)

在上一篇中,我们从理论和概念上详细的了解了LINQ的第二种架构“解释查询”。在这接下来的二个篇章中,我们将使用LINQ to SQL和Entity Framework来实践“解释查询”,学习这些技术的关键特性。在本系列文章中,我不准备事无巨细的讨论LINQ to SQL和Entity Framework的方方面面,毕竟那样需要太多的篇幅,也会让我们从LINQ上面转移注意力,况且,园子里也有不少介绍...

weixin_33690963的博客 438

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

asp.net MVC + linq to Entity简单教程(四)linq to Entity查询中其它方法的使用

在前面我们说到了,简单的列表显示,下面我们来介绍一下,一些其它的属性。   1, order by 的使用    在sql语句中,order by 语句是经常使用的。一般来说,它一般和top配对使用。这里我们介绍一下linq to Entity中如何使用order by             一般正常的sql语句应该是    [sql] view pl

qq_16518567的专栏 812
上一篇: .NET使用Action及Func泛型委托
下一篇: 如何规范.net中的js开发(1)概念篇(更新版)
ArvinStudy
博客等级 码龄15年 83粉丝 193原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值