.net EntityFramework通过多对多链接和嵌套表连接

时间:2013-07-05 20:56:20

标签: .net sql entity-framework many-to-many entity-framework-mapping

SQL查询,例如下面的SQL查询但使用实体框架?

SELECT     Software.Vendor, Software.Version, 
Rollout.ID, Software.Name, Rollout.Name 

FROM         org_User INNER JOIN
                      SoftwareUser ON org_User.ID = SoftwareUser.FK_org_User_ID INNER JOIN
                      Software ON Software.ID = SoftwareUser.FK_Software_ID INNER JOIN
                      AssetAssignee ON org_User.ID = AssetAssignee.FK_org_User_ID INNER JOIN
                      Rollout ON AssetAssignee.FK_Rollout_ID = Rollout.ID INNER JOIN
                      Location ON AssetAssignee.FK_Location_ID = Location.ID
WHERE     (Rollout.ID = 44) AND (Location.ID = 2)
GROUP BY Software.Vendor, Software.Version, 
Rollout.ID, Software.Name, Rollout.Name 

DB Schema(注意多对多表'SoftwareUser') DB schema

实体框架edmx模型(不会显示多对多的表'SoftwareUser',因为设计师承认它只是一个纯粹的多对多链接表,并用两端带星号的连接线来说明这一点)

enter image description here

我试图使用PredicateBuilder实用程序类,但是我在下面的方式变得非常明显,因为我无法以我使用它的方式构建查询。那里没有快乐。

 internal static List<Software> GetApplications(
        string UserID,
        string Surname,
        string Forname,
        int? TeamID,
        int? LocationID,
        int? RolloutID,
        string EmployeeID)
    {
        {
            var predicate = GetApplicationsPredicate(UserID, Surname, Forname, TeamID, LocationID, RolloutID, EmployeeID);

            using (ITAMEFContext db = new ITAMEFContext(ConnectionStrings.ITAM_ConnectionString_EF))
            {
                db.Configuration.ProxyCreationEnabled = false;

                return db.Softwares.Where(predicate).ToList();

            }
        }
    }

    private static Expression<Func<Software, bool>> GetApplicationsPredicate(
        string UserID,
        string Surname,
        string Forname,
        int? TeamID,
        int? LocationID,
        int? RolloutID,
        string EmployeeID)
    {
        var predicate = PredicateBuilder.True<Software>();

        bool nothingSelected = (
            TeamID == null
            && LocationID == null
            && RolloutID == null
            && string.IsNullOrEmpty(Surname)
            && string.IsNullOrEmpty(Forname)
            && string.IsNullOrEmpty(EmployeeID)
            && string.IsNullOrEmpty(UserID)
            );

        if (nothingSelected)
        {
            // we need to negate the first true predicate of we don't have any other predicates.
            predicate = predicate.And(u => !(nothingSelected));
            return predicate;
        }

        //if (!string.IsNullOrEmpty(UserID))
        //    predicate = predicate.And(s => s.org_User.Select(u => u.AssetAssignees.Any(aa => aa.org_User.DomainUserID.Contains(UserID))) != null);

        //if (!string.IsNullOrEmpty(Surname))
        //    predicate = predicate.And(s => s.org_User.Any(u => u.AssetAssignees.Any(aa => aa.org_User.Surname.Contains(Surname))));

        //if (!string.IsNullOrEmpty(Forname))
        //    predicate = predicate.And(s => s.org_User.Any(u => u.AssetAssignees.Any(aa => aa.org_User.Forename.Contains(Forname)))); ;

        //if (!string.IsNullOrEmpty(EmployeeID))
        //    predicate = predicate.And(s => s.org_User.Any(u => u.AssetAssignees.Any(aa => aa.org_User.EmployeeID.Contains(EmployeeID))));

        if (LocationID.HasValue)
            predicate = predicate.And(s => s.org_User.Any(u => u.AssetAssignees.Any(aa => aa.Location.ID == LocationID.Value)));

        //if (TeamID.HasValue)
        //    predicate = predicate.And(s => s.org_User.Any(u => u.AssetAssignees.Any(aa => aa.org_User.org_Team.ID == TeamID.Value)));

        if (RolloutID.HasValue)
            predicate = predicate.And(s => s.org_User.Any(u => u.AssetAssignees.Any(aa => aa.Rollout.ID == RolloutID)));

        //if (RolloutID.HasValue)
        //    predicate = predicate.And(s => s.org_User.Any(u => u.AssetAssignees.Any(aa => aa.Rollout.ID == RolloutID)));

        return predicate;
    }

但这只会导致生成以下不适当的SQL。

    SELECT 
[Extent1].[ID] AS [ID], 
[Extent1].[FK_ApptrackerID] AS [FK_ApptrackerID], 
[Extent1].[FK_SoftwareType_ID] AS [FK_SoftwareType_ID], 
[Extent1].[Name] AS [Name], 
[Extent1].[Vendor] AS [Vendor], 
[Extent1].[Version] AS [Version], 
[Extent1].[Ready] AS [Ready]
FROM [dbo].[Software] AS [Extent1]
WHERE 
( EXISTS (SELECT 
    1 AS [C1]
    FROM ( SELECT 
        [Extent2].[FK_org_User_ID] AS [FK_org_User_ID]
        FROM [dbo].[SoftwareUser] AS [Extent2]
        WHERE [Extent1].[ID] = [Extent2].[FK_Software_ID]
    )  AS [Project1]
    WHERE  EXISTS (SELECT 
        1 AS [C1]
        FROM [dbo].[AssetAssignee] AS [Extent3]
        WHERE ([Project1].[FK_org_User_ID] = [Extent3].[FK_org_User_ID]) AND ([Extent3].[FK_Location_ID] = 2)
    )
)) 

AND 

( EXISTS (SELECT 
    1 AS [C1]
    FROM ( SELECT 
        [Extent4].[FK_org_User_ID] AS [FK_org_User_ID]
        FROM [dbo].[SoftwareUser] AS [Extent4]
        WHERE [Extent1].[ID] = [Extent4].[FK_Software_ID]
    )  AS [Project4]
    WHERE  EXISTS (SELECT 
        1 AS [C1]
        FROM [dbo].[AssetAssignee] AS [Extent5]
        WHERE ([Project4].[FK_org_User_ID] = [Extent5].[FK_org_User_ID]) AND ([Extent5].[FK_Rollout_ID] = 44)
    )
))

请帮助:'(

EF dll版本4.4.0.0 | 方法 - 数据库优先| .net 4.0

2 个答案:

答案 0 :(得分:1)

有些查询无法在EF中编写,但您显示的查询实际上并不那么难,尤其是。不是在使用查询语法并利用导航属性的力量时:

from ou in db.org_User
from sw in ou.Softwares
from aa in ou.AssetAssignees
select new { sw.Vendor, sw.Version, aa.Rollout.ID, aa.Rollout.Name }

您不需要group by,因为您选择的字段与您分组的字段完全相同。你也不需要访问联结表,因为EF会为你加入。

如果要应用谓词,可以通过

启动语句
from ou in db.org_User.Where(predicate)

答案 1 :(得分:0)

我最终确定了以下查询语法,这似乎带回了正确的结果。

internal static List<Software> GetApplications(
            string UserID,
            string Surname,
            string Forname,
            int? TeamID,
            int? LocationID,
            int? RolloutID,
            string EmployeeID)
        {
            {

                using (ITAMEFContext db = new ITAMEFContext(ConnectionStrings.ITAM_ConnectionString_EF))
                {
                    db.Configuration.ProxyCreationEnabled = false;

                    return (from ou in db.org_User
                           from sw in ou.Softwares
                           from aa in ou.AssetAssignees
                           where aa.org_User.DomainUserID.Contains(UserID)
                           &&
                           (!TeamID.HasValue || aa.org_User.org_Team.ID == TeamID)
                           &&
                           (!LocationID.HasValue || aa.org_User.Location.ID == LocationID.Value)
                           &&
                           (!RolloutID.HasValue || aa.Rollout.ID == RolloutID)
                           &&
                           aa.org_User.Surname.Contains(Surname)
                           &&
                           aa.org_User.Forename.Contains(Forname)
                           &&
                           aa.org_User.EmployeeID.Contains(EmployeeID)
                           group sw by sw.ID into swG

                           select swG).Select(g => g.FirstOrDefault()).ToList();

                }
            }
        }