简体   繁体   English

如何在Entity Framework中加入对象

[英]How to do join with objects in Entity Framework

So I am converting a old project with ordinary SQL queries to a ORM using the Entity Framework. 因此,我正在使用实体框架将具有普通SQL查询的旧项目转换为ORM。 So I have created database model like this: 所以我创建了这样的数据库模型:

数据库模型

So I had this old query which I want to translate to a linq expression 所以我有这个旧的查询,我想转换为linq表达式

SELECT UGLINK.USERNAME 
FROM GMLINK 
INNER JOIN UGLINK 
ON GMLINK.GROUPID = UGLINK.GROUPID 
WHERE (((GMLINK.MODULEID)=%ID%))

And the problem I have is that I can't figure out how to do a join query using the objects. 我遇到的问题是我无法弄清楚如何使用对象进行连接查询。 Instead I have to go though the properties like this (which seems to be working): 相反,我必须通过这样的属性(似乎工作):

// So this is one of the module objects that is located in a listView in the GUI
Module m = ModuleList.selectedItem as Module;

/* Now I want to fetch all the User objects that, 
 * via a group, is connected to a certain module */
var query = context.gmLink
    .Join(context.ugLink,
          gmlink => gmlink.GroupId,
          uglink => uglink.GroupId,
          (gmlink, uglink) => new { gmLink = gmlink, ugLink = uglink })
    .Where(gmlink => gmlink.gmLink.ModuleId == m.ModuleId)
    .Select(x => x.ugLink.User);

So as I said this works, but as you see I kind of have to connect the modules via the link tables properties .GroupId and .ModuleId and so on. 正如我所说的那样有效,但正如你所看到的那样,我必须通过链接表属性.GroupId.ModuleId等连接模块。 Instead I would like to go through the objects created by EF. 相反,我想通过EF创建的对象。

I wanted to write a question a bit like this, but can't figure out how to do it, is it at all possible? 我想写一个类似这样的问题,但无法弄清楚如何做到这一点,它是否可能?

var query = context.User
            .Select(u => u.ugLink
                .Select(uglink => uglink.Group.gmLink
                    .Where(gmLink => gmLink.Module == m)));

If you have lazy loading enabled, you do not need to apply specific join notation (you can access the navigation properties directly) - but the queries that are ran against SQL are inefficient (generally the results are returned in a number of different select statements). 如果启用了延迟加载,则不需要应用特定的连接表示法(可以直接访问导航属性) - 但针对SQL运行的查询效率低下(通常结果会在许多不同的select语句中返回) 。

My preference is to disable lazy loading on the context, and use .Include() notation to join tables together manually, resulting in generally more efficient queries. 我的偏好是在上下文中禁用延迟加载,并使用.Include()表示法手动将表连接在一起,从而通常可以提高查询效率。 .Include() is used to explicitly join entities in Entity Framework. .Include()用于显式连接Entity Framework中的实体。

Join() is misleading, and not appropriate for joining tables in EF. Join()具有误导性,不适合在EF中连接表。

So, to replicate this statement: 所以,要复制这个声明:

SELECT UGLINK.USERNAME 
FROM GMLINK 
INNER JOIN UGLINK 
ON GMLINK.GROUPID = UGLINK.GROUPID 
WHERE (((GMLINK.MODULEID)=%ID%))

You would use the following: 您将使用以下内容:

var query = context.gmLink
    .Include(x => x.Group.gmLink)
    .Where(x => x.ModuleId == myIdVariable)
    .Select(x => new {
        UserName = x.Group.ugLink.UserName
    });

Assuming that your navigation properties are correctly set up. 假设您的导航属性已正确设置。 I have not tested this, so I'm not 100% on the syntax. 我没有测试过这个,所以我不是100%的语法。

You should really run SQL profiler while you write and run LINQ to Entity queries against your database, so you can understand what's actually being generated and run against your database. 在编写和运行针对数据库的LINQ to Entity查询时,您应该真正运行SQL事件探查器,这样您就可以了解实际生成的内容并针对您的数据库运行。 A lot of the time, an EF query may be functioning correctly, but you may experience performance issues when deployed to a production system. 很多时候,EF查询可能正常运行,但在部署到生产系统时可能会遇到性能问题。

This whitepaper might help you out. 本白皮书可能会帮助您。

This should be working: 这应该是有效的:

var query = context.gmLink
    .Where(gmlink => gmlink.ModuleId == m.ModuleId)
    .SelectMany(gmlink => gmlink.Group.ugLink)
    .Select(uglink => uglink.User);

It's impossible to filter gmLinks using .Where(gmlink => gmlink.Module == m) in EF, so this comparison needs to be done using identifiers. 在EF中使用.Where(gmlink => gmlink.Module == m)过滤gmLink是不可能的,因此需要使用标识符进行比较。 Another option is .Where(gmlink => gmlink.Module.ModuleId == m.ModuleId) 另一个选项是.Where(gmlink => gmlink.Module.ModuleId == m.ModuleId)

I haven't tested it, but something like this: 我还没有测试过,但是这样的话:

var users = context.User
    .Where(x => x.ugLink
        .Any(y => context.gmLink
                    .Where(z => z.ModuleId == m)
                    .Select(z => z.GroupId)
                    .Contains(y.GroupId)
        )
    )
    .ToList();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM