(EFCore使⽤Include和join)(Include和ThenInclude区别)
EF Core使⽤Include和join
在EF中表连接常⽤的有Join()和Include(),两者都可以实现两张表的连接,但⼜有所不同。
例如有个唱⽚表Album(AlbumId,Name,CreateDate,GenreId),表中含外键GenreId连接流派表Genre(GenreId,Name)。每个唱⽚归属唯⼀⼀个流派,⼀个流派可以对应多个唱⽚。
1.Join():
两表不必含有外键关系,需要代码⼿动指定连接外键相等(具有可拓展性,除了值相等,还能指定是>,<;以及其他对两表的相应键的关系),以及结果字段。
那么可以这么写两个表的连接:
var wholeRecord = dc.Album.Join(dc.Genre, a => a.GenreId, g => g.GenreId,(a, g)=>new{ a.AlbumId,a.Name,g.GenreId,g.Name;
这样就选取除了两表的AlbumId,Name,GenreId,Name。
2.Include():
两表必须含有外键关系,只需要指定键名对应的类属性名即可,不需指定结果字段(即全部映射)。默认搜索某表时,不会顺带查询外键表,直到真正使⽤时才会再读取数据库查询;若是使⽤ Include(),则会在读取本表时把指定的外键表信息也读出来。
那么可以这么写两个表的连接:
//EF已经⽣成了Album和Genre的数据库映射模型类以及导航属性
var wholeRecord=dc.Album.Include("Genre");
//或者
//var wholeRecord=dc.Album.Include(a=>Genre);
这样数据库就执⾏了⼀个左连接,把Album和Genre的所有字段全部连起来了,并且Include()是⽴即查询的,像ToList()⼀样,不会稍后延迟优化后再加载。
这样其实效率很低,因为如果两张表记录很⼤,那么连接是个费时费资源的事情,建议少⽤,或者先筛选出需要的结果集再连接。Include和ThenInclude区别
“Include”在我们不需要多级数据的对象上运⾏良好,但如果需要获得多级数据,那么“ThenInclude”是最合适的。让我⽤⼀个例⼦解释⼀下。假设我们有3个实体,公司,客户经理和顾客:
public class Company
{
public string Name {get;t;}
public class Manager{get;t;}
}
public class Manager
{
public string Name {get;t;}
public class Client {get;t;}
}
public class Client
{
public string Name {get;t;}
public string ClientMessage {get;t;}
}
现在,如果你想公司和公司下的客户经理你可以像下⾯那样使⽤“Include”,这样你拿到的是company的name和Manager的name
using(var context =new YourContext())
{
var customers = context.Company
.Include(c => c.Clients)
.ToList();
}
但是如果您想要公司和客户经理以及顾客,因为顾客没有直接和公司关联,所以不能使⽤include直接关联到,这时候您可以使
⽤“ThenInclude”,这样你拿到的就是company的name和Manager的name还有Client的ClientMessage
using(var context =new MyContext())
{
var customers = context.Company
.Include(i => i.Manager )
.ThenInclude(a => a.ClientMessage )
.ToList();
}
这相当于⽤关联出来的manager去关联client
EF的表左连接⽅法Include和Join
在EF中表连接常⽤的有Join()和Include(),两者都可以实现两张表的连接,但⼜有所不同。
例如有个唱⽚表Album(AlbumId,Name,CreateDate,GenreId),表中含外键GenreId连接流派表Genre(GenreId,Name)。每个唱⽚归属唯⼀⼀个流派,⼀个流派可以对应多个唱⽚。
1.Join(),两表不必含有外键关系,需要代码⼿动指定连接外键相等(具有可拓展性,除了值相等,还能指定是>,<;以及其他对两表的相应键的关系),以及结果字段。
重载⽅式(是扩展⽅法,第⼀个参数带this,代表⾃⾝):
1.
public static IQueryable<TResult>Join<TOuter, TInner, TKey, TResult>(this IQueryable<TOuter> outer, IEnumerable<TInner> inner, Expression<Func<TO uter, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<TOuter, TInner, TResult>> resultSelector);
2.
public static IQueryable<TResult>Join<TOuter, TInner, TKey, TResult>(this IQueryable<TOuter> outer, IEnumerable<TInner> inner, Expression<Func<TO uter, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<TOuter, TInner, TResult>> resultSelector, IEquality Comparer<TKey> comparer);
那么可以这么写两个表的连接:
var wholeRecord = dc.Album.Join(dc.Genre, a => a.GenreId, g => g.GenreId,(a, g)=>new{ a.AlbumId,a.Name,g.GenreId,g.Name;
这样就选取除了两表的AlbumId,Name,GenreId,Name。
2.Include(),两表必须含有外键关系,只需要指定键名对应的类属性名即可,不需指定结果字段(即全部映射)。默认搜索某表时,不会顺带查询外键表,直到真正使⽤时才会再读取数据库查询;若是使⽤ Include(),则会在读取本表时把指定的外键表信息也读出来。
重载⽅式:
//位于namespace System.Data.Entity.Infrastructure
public DbQuery<TResult>Include(string path);
关雎和蒹葭//位于namespace System.Data.Entity,务必引⼊才能找到该⽅法。否则只看到上个⽅法
public static IQueryable<T>Include<T, TProperty>(this IQueryable<T> source, Expression<Func<T, TProperty>> path)where T :class;
public static IQueryable<T>Include<T>(this IQueryable<T> source,string path)where T :class;
可以这么写:
//EF已经⽣成了Album和Genre的数据库映射模型类以及导航属性
var wholeRecord=dc.Album.Include("Genre");
//或者
//var wholeRecord=dc.Album.Include(a=>Genre);
这样数据库就执⾏了⼀个左连接,把Album和Genre的所有字段全部连起来了,并且Include()是⽴即查询的,像ToList()⼀样,不会稍后延迟优化后再加载。
这样其实效率很低,因为如果两张表记录很⼤,那么连接是个费时费资源的事情,建议少⽤,或者先
筛选出需要的结果集再连接。
EF的Join()和Include()差异
在EF中表连接常⽤的有Join()和Include(),两者都可以实现两张表的连接,但⼜有所不同。
1.Join(),两表不必含有外键关系,需要代码⼿动指定连接外键相等(具有可拓展性,除了值相等,还能指定是>,<;以及其他对两表的相应键的关系),以及结果字段。
2.Include(),两表必须含有外键关系,只需要指定键名对应的类属性名即可,不需指定结果字段(即全部映射)。默认搜索某表时,不会顺带查询外键表,直到真正使⽤时才会再读取数据库查询;若是使⽤ Include(),则会在读取本表时把指定的外键表信息也读出来。Include
1、现在有三张表
Math_RoleInfo ⾓⾊表
Math_Ur_Role_Select ⽤户⾓⾊选择表
Math_UrInfo ⽤户表
如何通过单个⾓⾊,获取⽤户信息呢。通过EF。
C#代码如下
Guid id = Guid.Par("815D30FB-1050-413D-9E19-D8CBDC434E7C");
MathRoleAuthorEntities context =new MathRoleAuthorEntities();
List<Math_RoleInfo> list = context.Math_RoleInfo.Include("Math_Ur_Role_Select").Include("Math_Ur_Role_Select.Math_UrInfo").Where(item => ite m.RoleId== id).ToList<Math_RoleInfo>();
Console.ReadKey();
第⼀次的include是单级的导航属性,
第⼆次include是多级的导航属性。中间⽤.进⾏级别的传递。
JOIN
在EF中,当在dbt使⽤join关联多表查询时,连接查询的表如果没有建⽴相应的外键关系时,EF⽣
成的SQL语句是inner join(内联),对于inner join,有所了解的同学都知道,很多时候这并不是我们的本意,实例如下:
var list =from o in context.CTMS_OD_ORDERS
join d in context.CTMS_SUP_DOCTOR
on o.OWNERDOCID equals d.USERID
join e in context.CTMS_OD_ORDERSEVALUATION润滑油十大品牌排行榜
on o.ORDERID equals e.ORDERID
lect o;`
EF⽣成了内连接(inner join)查询,当两个表的任⼀表的数据不匹配时,查询结果就为空!实际上left join(左联接)才是我们想要的,那么怎么样才能⽣成left join查询呢?其实只要我们如下改造,EF就能为我们⽣成left join(左联接)查询!
data =from o in context.CTMS_OD_ORDERS
join d in context.CTMS_SUP_DOCTOR
on o.OWNERDOCID equals d.USERID into dc
from dci in dc.DefaultIfEmpty()
join e in context.CTMS_OD_ORDERSEVALUATION
on o.ORDERID equals e.ORDERID into ec
from eci in ec.DefaultIfEmpty()
where o.USERID == urID &&(string.IsNullOrEmpty(type)|| o.PRODUCTNAME.Contains(type))
lect new ODOrders
{
BalanceStatus = o.BALANCESTATUS,
ChannelOrderID = o.CHANNELORDERID,
ChannelType = o.CHANNELTYPE,
CreateDateTime = o.CREATEDATETIME,
CreateUrID = o.CREATEUSERID,
豆沙面包卷
CreateUrName = o.CREATEUSERNAME,
DocName = dci.DOCNAME,
EvalutionStatus =string.IsNullOrEmpty(eci.ORDERID)?"0":"1",电脑阅卷
PayTime = o.PAYTIME,
怎么做幻灯片ProductCode = o.PRODUCTCODE,
ProductName = o.PRODUCTNAME,
ProductInstanceId = o.PRODUCTINSTANCEID,
ProductID = o.PRODUCTID,
OrderID = o.ORDERID,
OrderCode = o.ORDERCODE,
OrderStatus = o.ORDERSTATUS,
OrderType=o.ORDERTYPE,
TotalFee = o.TOTALFEE,
UrID=o.USERID,
UrName=o.USERNAME
};
对⽐上下两种写法,可以看到在on表的后⾯我们加上了into xx,还有不要忘记,还需加上from xxx in xx.DefaultIfEmpty(),重要的就是最后的xx.DefaultIfEmpty(),它的作⽤是当连接的表为空时也会有⼀条空的数据,达到了left join的效果。
EF之外键Include()left join
项⽬中⽤EF实现外键查询出的数据, 查询数量正确, 但实现返回数据集数量不对教室的英语
//DbContext.cs
HasRequired(s => s.ClassRoom)
.WithMany()
.HasForeignKey(student => student.ClassRoomId);
//查询语句
dbRead.Set<Student>().Include(x=>x.ClassRoom);
精力成本查询 .Count()和.ToList()结果数量不⼀致
经调试后发现⽣成的Sql语句为 inner join
正确的结果应该是 left join
此时应该如下定义外键
HasOptional(s => s.ClassRoom)
.WithMany()
.HasForeignKey(student => student.ClassRoomId);
闸坡大角湾此时返回的结果就正确了!