Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unnecessary join in Entity framework when using imported function?

I have an Employee table in my database and a SQL table value function that return exactly same structure as my employee table. I'm changing some fields value (Like GroupNumber) of table in my function. I imported the function in EF and set return type To Employee entity.
Now I run the following query:

IQueryable<Employee> employeeSearchResult = this.Context.EmployeeStateAtDate(persianDate.ToDateTime());
var result = employeeSearchResult.Where(q => q.Group.Title.contains("XYZ")).Select(q => q.EmployeeN umber).ToList()

The query generated is as the following

SELECT  [Filter1].[EmployeeNumber1] AS [EmployeeNumber]
FROM    ( 
            SELECT      [Extent1].[EmployeeNumber] AS [EmployeeNumber1] ,
                        [Extent2].[GroupNumber] AS [GroupNumber1]
            FROM        [dbo].[kara_emp_EmployeeStateAtDate](@Date) AS [Extent1]
                            LEFT OUTER JOIN [dbo].[Employee] AS [Extent2] ON ( [Extent2].[GroupNumber] IS NOT NULL )
                                                              AND ( [Extent1].[EmployeeNumber] = [Extent2].[EmployeeNumber] )
        ) AS [Filter1]
        INNER JOIN [dbo].[Groups] AS [Extent3] ON [Filter1].[GroupNumber1] = [Extent3].[GroupNumber]
WHERE   [Extent3].[Title] LIKE N'%XYZ%'

I dont know why, but EF joins function with Employee table again and take GroupNumber field from Employee table.

SELECT      [Extent1].[EmployeeNumber] AS [EmployeeNumber1] ,
                            [Extent2].[GroupNumber] AS [GroupNumber1]
                FROM        [dbo].[kara_emp_EmployeeStateAtDate](@Date) AS [Extent1]
                                LEFT OUTER JOIN [dbo].[Employee] AS [Extent2] ON ( [Extent2].[GroupNumber] IS NOT NULL )
                                                                  AND ( [Extent1].[EmployeeNumber] = [Extent2].[EmployeeNumber] )

It causes wrong vlaue, beacuse I changed GroupNumber value in the function.
Why EF joins function with Employee table again?

Edit: TSql generated with the following code:

IQueryable<Employee> employeeSearchResult = this.Context.EmployeeStateAtDate(persianDate.ToDateTime());
    var result = employeeSearchResult.Where(q => q.Group.Title.contains("XYZ")).ToList()


SELECT 
    [Filter1].[Emp_No1] AS [Emp_No], 
    [Filter1].[Pers_No1] AS [Pers_No], 
    [Filter1].[Name1] AS [Name], 
    [Filter1].[Family1] AS [Family], 
    [Filter1].[NationalId1] AS [NationalId], 
    [Filter1].[MobileNumber1] AS [MobileNumber], 
    [Filter1].[Email1] AS [Email], 
    [Filter1].[Address1] AS [Address], 
    [Filter1].[Tel1] AS [Tel], 
    [Filter1].[Emp_Date1] AS [Emp_Date], 
    [Filter1].[End_Date1] AS [End_Date], 
    [Filter1].[Birth_Date1] AS [Birth_Date], 
    [Filter1].[Pos_No1] AS [Pos_No], 
    [Filter1].[Sec_No1] AS [Sec_No], 
    [Filter1].[Grade_No1] AS [Grade_No], 
    [Filter1].[Emp_Type1] AS [Emp_Type], 
    [Filter1].[IsCut1] AS [IsCut], 
    [Filter1].[Cut_Reason1] AS [Cut_Reason], 
    [Filter1].[HasBreakfast1] AS [HasBreakfast], 
    [Filter1].[HasLunch1] AS [HasLunch], 
    [Filter1].[HasDinner1] AS [HasDinner], 
    [Filter1].[DelayFloatingTime1] AS [DelayFloatingTime], 
    [Filter1].[HurryFloatingTime1] AS [HurryFloatingTime], 
    [Filter1].[ExitFloatingTime1] AS [ExitFloatingTime], 
    [Filter1].[MaxFloatingTime1] AS [MaxFloatingTime], 
    [Filter1].[MaxFloatingCount1] AS [MaxFloatingCount], 
    [Filter1].[FloatingToMor1] AS [FloatingToMor], 
    [Filter1].[InformWay1] AS [InformWay], 
    [Filter1].[InformGh1] AS [InformGh], 
    [Filter1].[InformMorMam1] AS [InformMorMam], 
    [Filter1].[InformIO1] AS [InformIO], 
    [Filter1].[Is_Karmand1] AS [Is_Karmand], 
    [Filter1].[Sys_Active1] AS [Sys_Active], 
    [Filter1].[Esteh_Save_Main1] AS [Esteh_Save_Main], 
    [Filter1].[Esteh_Save1] AS [Esteh_Save], 
    [Filter1].[Min_Shab1] AS [Min_Shab], 
    [Filter1].[Is_Janbaz1] AS [Is_Janbaz], 
    [Filter1].[Janbaz_Tim1] AS [Janbaz_Tim], 
     CAST( [Filter1].[Janbaz_E_T1] AS smallint) AS [C1], 
    [Filter1].[Grp_No1] AS [Grp_No], 
    [Filter1].[Sabet_Ez1] AS [Sabet_Ez], 
    [Filter1].[Nbat_Prsnt1] AS [Nbat_Prsnt], 
    [Filter1].[Fix_Kar1] AS [Fix_Kar], 
    [Filter1].[Is_Uniq1] AS [Is_Uniq], 
    [Filter1].[Karkerd31] AS [Karkerd3], 
    [Filter1].[Grp1_No1] AS [Grp1_No], 
    [Filter1].[Grp2_No1] AS [Grp2_No], 
    [Filter1].[Grp3_No1] AS [Grp3_No], 
    [Filter1].[Grp4_No1] AS [Grp4_No], 
    [Filter1].[Grp5_No1] AS [Grp5_No], 
    [Filter1].[Ez_Type1] AS [Ez_Type], 
    [Filter1].[Mazad_Time1] AS [Mazad_Time], 
    [Filter1].[Prev_BNOver1] AS [Prev_BNOver], 
    [Filter1].[After_BNOver1] AS [After_BNOver], 
    [Filter1].[Bain_BNOver1] AS [Bain_BNOver], 
    [Filter1].[Holiday_BNOver1] AS [Holiday_BNOver], 
    [Filter1].[Almosanna1] AS [Almosanna], 
    [Filter1].[Barcode1] AS [Barcode], 
    [Filter1].[Holiday_KasrEsth1] AS [Holiday_KasrEsth], 
    [Filter1].[Kasr_EsthType1] AS [Kasr_EsthType], 
    [Filter1].[Kasr_Esth1] AS [Kasr_Esth], 
    [Filter1].[Gender1] AS [Gender], 
    [Filter1].[HurryTime1] AS [HurryTime], 
    [Filter1].[IsNaft1] AS [IsNaft], 
    [Filter1].[NaftKasrKh1] AS [NaftKasrKh], 
    [Filter1].[NaftIncKh1] AS [NaftIncKh], 
    [Filter1].[NaftKhPlace1] AS [NaftKhPlace], 
    [Filter1].[DelayTime1] AS [DelayTime], 
    [Filter1].[ServiceNumber1] AS [ServiceNumber], 
    [Filter1].[Mazad_TimeRz1] AS [Mazad_TimeRz], 
    [Filter1].[MinPrevOver1] AS [MinPrevOver], 
    [Filter1].[MinBainOver1] AS [MinBainOver], 
    [Filter1].[MinAfterOver1] AS [MinAfterOver], 
    [Filter1].[MinHolidOver1] AS [MinHolidOver], 
    [Filter1].[FloatingType1] AS [FloatingType], 
    [Filter1].[MaxDayOver1] AS [MaxDayOver], 
    [Filter1].[MaxHolidOver1] AS [MaxHolidOver], 
    [Filter1].[Mazad_TimeR1] AS [Mazad_TimeR], 
    [Filter1].[Holiday_KasrBh1] AS [Holiday_KasrBh], 
    [Filter1].[HospitalProductivityId1] AS [HospitalProductivityId], 
    [Filter1].[MJobran1] AS [MJobran], 
    [Filter1].[RJobran1] AS [RJobran], 
    [Filter1].[WF_SpecialKartabl1] AS [WF_SpecialKartabl], 
    [Filter1].[MonthOfKhedmat1] AS [MonthOfKhedmat], 
    [Filter1].[HardWorkPercent1] AS [HardWorkPercent], 
    [Filter1].[HasUnusualTurnShift1] AS [HasUnusualTurnShift], 
    [Filter1].[MaxHardWorkMors1] AS [MaxHardWorkMors], 
    [Filter1].[UserDevicePassword1] AS [UserDevicePassword], 
    [Filter1].[UserDevicePrivilage1] AS [UserDevicePrivilage], 
    [Filter1].[UserDeviceEnabled1] AS [UserDeviceEnabled], 
    [Filter1].[Ejbari_Mor1] AS [Ejbari_Mor], 
    [Filter1].[UserDeviceAuth1] AS [UserDeviceAuth], 
    [Filter1].[UserDeviceCardId1] AS [UserDeviceCardId], 
    [Filter1].[MilkFeedingTime1] AS [MilkFeedingTime], 
    [Filter1].[MilkFeedingStartDate1] AS [MilkFeedingStartDate], 
    [Filter1].[MilkFeedingEndDate1] AS [MilkFeedingEndDate]
    FROM   (SELECT [Extent1].[Emp_No] AS [Emp_No1], [Extent1].[Pers_No] AS [Pers_No1], [Extent1].[Name] AS [Name1], [Extent1].[Family] AS [Family1], [Extent1].[NationalId] AS [NationalId1], [Extent1].[MobileNumber] AS [MobileNumber1], [Extent1].[Email] AS [Email1], [Extent1].[Address] AS [Address1], [Extent1].[Tel] AS [Tel1], [Extent1].[Emp_Date] AS [Emp_Date1], [Extent1].[End_Date] AS [End_Date1], [Extent1].[Birth_Date] AS [Birth_Date1], [Extent1].[Pos_No] AS [Pos_No1], [Extent1].[Sec_No] AS [Sec_No1], [Extent1].[Grade_No] AS [Grade_No1], [Extent1].[Emp_Type] AS [Emp_Type1], [Extent1].[Gender] AS [Gender1], [Extent1].[IsCut] AS [IsCut1], [Extent1].[Cut_Reason] AS [Cut_Reason1], [Extent1].[HasBreakfast] AS [HasBreakfast1], [Extent1].[HasLunch] AS [HasLunch1], [Extent1].[HasDinner] AS [HasDinner1], [Extent1].[DelayTime] AS [DelayTime1], [Extent1].[HurryTime] AS [HurryTime1], [Extent1].[FloatingType] AS [FloatingType1], [Extent1].[MJobran] AS [MJobran1], [Extent1].[RJobran] AS [RJobran1], [Extent1].[DelayFloatingTime] AS [DelayFloatingTime1], [Extent1].[HurryFloatingTime] AS [HurryFloatingTime1], [Extent1].[ExitFloatingTime] AS [ExitFloatingTime1], [Extent1].[MaxFloatingTime] AS [MaxFloatingTime1], [Extent1].[MaxFloatingCount] AS [MaxFloatingCount1], [Extent1].[FloatingToMor] AS [FloatingToMor1], [Extent1].[MaxDayOver] AS [MaxDayOver1], [Extent1].[MaxHolidOver] AS [MaxHolidOver1], [Extent1].[MinPrevOver] AS [MinPrevOver1], [Extent1].[MinBainOver] AS [MinBainOver1], [Extent1].[MinAfterOver] AS [MinAfterOver1], [Extent1].[MinHolidOver] AS [MinHolidOver1], [Extent1].[Prev_BNOver] AS [Prev_BNOver1], [Extent1].[After_BNOver] AS [After_BNOver1], [Extent1].[Bain_BNOver] AS [Bain_BNOver1], [Extent1].[Holiday_BNOver] AS [Holiday_BNOver1], [Extent1].[Min_Shab] AS [Min_Shab1], [Extent1].[Ez_Type] AS [Ez_Type1], [Extent1].[Mazad_Time] AS [Mazad_Time1], [Extent1].[Mazad_TimeR] AS [Mazad_TimeR1], [Extent1].[Mazad_TimeRz] AS [Mazad_TimeRz1], [Extent1].[InformWay] AS [InformWay1], [Extent1].[InformGh] AS [InformGh1], [Extent1].[InformMorMam] AS [InformMorMam1], [Extent1].[InformIO] AS [InformIO1], [Extent1].[Is_Karmand] AS [Is_Karmand1], [Extent1].[Sys_Active] AS [Sys_Active1], [Extent1].[Esteh_Save_Main] AS [Esteh_Save_Main1], [Extent1].[Esteh_Save] AS [Esteh_Save1], [Extent1].[Is_Janbaz] AS [Is_Janbaz1], [Extent1].[Janbaz_Tim] AS [Janbaz_Tim1], [Extent1].[Janbaz_E_T] AS [Janbaz_E_T1], [Extent1].[Grp_No] AS [Grp_No1], [Extent1].[Sabet_Ez] AS [Sabet_Ez1], [Extent1].[Nbat_Prsnt] AS [Nbat_Prsnt1], [Extent1].[Fix_Kar] AS [Fix_Kar1], [Extent1].[Is_Uniq] AS [Is_Uniq1], [Extent1].[Karkerd3] AS [Karkerd31], [Extent1].[Grp1_No] AS [Grp1_No1], [Extent1].[Grp2_No] AS [Grp2_No1], [Extent1].[Grp3_No] AS [Grp3_No1], [Extent1].[Grp4_No] AS [Grp4_No1], [Extent1].[Grp5_No] AS [Grp5_No1], [Extent1].[Almosanna] AS [Almosanna1], [Extent1].[Barcode] AS [Barcode1], [Extent1].[Kasr_EsthType] AS [Kasr_EsthType1], [Extent1].[Kasr_Esth] AS [Kasr_Esth1], [Extent1].[Holiday_KasrEsth] AS [Holiday_KasrEsth1], [Extent1].[Holiday_KasrBh] AS [Holiday_KasrBh1], [Extent1].[ServiceNumber] AS [ServiceNumber1], [Extent1].[MonthOfKhedmat] AS [MonthOfKhedmat1], [Extent1].[HardWorkPercent] AS [HardWorkPercent1], [Extent1].[HasUnusualTurnShift] AS [HasUnusualTurnShift1], [Extent1].[HospitalProductivityId] AS [HospitalProductivityId1], [Extent1].[IsNaft] AS [IsNaft1], [Extent1].[NaftKasrKh] AS [NaftKasrKh1], [Extent1].[NaftIncKh] AS [NaftIncKh1], [Extent1].[NaftKhPlace] AS [NaftKhPlace1], [Extent1].[MaxHardWorkMors] AS [MaxHardWorkMors1], [Extent1].[UserDevicePassword] AS [UserDevicePassword1], [Extent1].[UserDevicePrivilage] AS [UserDevicePrivilage1], [Extent1].[UserDeviceEnabled] AS [UserDeviceEnabled1], [Extent1].[UserDeviceAuth] AS [UserDeviceAuth1], [Extent1].[UserDeviceCardId] AS [UserDeviceCardId1], [Extent1].[Ejbari_Mor] AS [Ejbari_Mor1], [Extent1].[MilkFeedingTime] AS [MilkFeedingTime1], [Extent1].[MilkFeedingStartDate] AS [MilkFeedingStartDate1], [Extent1].[MilkFeedingEndDate] AS [MilkFeedingEndDate1], [Extent1].[WF_SpecialKartabl] AS [WF_SpecialKartabl1], [Extent2].[Grp_No] AS [Grp_No2]
        FROM  [dbo].[kara_emp_EmployeeStateAtDate](@Date) AS [Extent1]
        LEFT OUTER JOIN [dbo].[Employee] AS [Extent2] ON ([Extent2].[Grp_No] IS NOT NULL) AND ([Extent1].[Emp_No] = [Extent2].[Emp_No])
        ) AS [Filter1]
    INNER JOIN [dbo].[Groups] AS [Extent3] ON [Filter1].[Grp_No2] = [Extent3].[Grp_No]
    WHERE [Extent3].[Title] LIKE N'%XYZ%'


-- Date: '2016/05/02 10:16:22 ق.ظ' (Type = DateTime2)

-- Executing at 2016/05/02 10:16:31 ق.ظ +04:30

-- Completed in 31 ms with result: SqlDataReader

Edit2: Data model is like this:

   public partial class Employee : Kara.Data.EntityBaseType
{
    public int EmployeeNumber { get; set; }
    public int? GroupNumber { get; set; }
    public int Pers_No { get; set; }
    public string Name { get; set; }
    public string Family { get; set; }
    public virtual Group Group { get; set; }
}
public partial class Group : Kara.Data.EntityBaseType
{
    public string Title { get; set; }
    public short GroupNumber { get; set; }
    public virtual List<Employee> Employees { get; set; }
}

And this is T-SQL of function

CREATE FUNCTION [dbo].[kara_emp_EmployeeStateAtDate]
(   
    @Date   DATETIME 
)
RETURNS TABLE 
AS
RETURN 
(
SELECT e.[EmployeeNumber]
      ,e.[Pers_No]
      ,e.[Name]
      ,e.[Family]
      , CASE  
            WHEN eg.GroupNumber IS NOT NULL THEN eg.GroupNumber
            ELSE e.GroupNumber
        END AS GroupNumber
      FROM [Employee] AS e 
        LEFT OUTER JOIN 
        (
            SELECT  eg.EmployeeNumber, eg.NewGroupNumber AS GroupNumber
            FROM    EmpGrps AS eg
                    INNER JOIN 
                    (
                        SELECT      eg3.EmployeeNumber, MAX(eg3.[DateStandard]) AS [DateStandard]
                        FROM        EmpGrps AS eg3
                        WHERE       eg3.[DateStandard] < ISNULL(@Date, GETDATE())
                        GROUP BY    eg3.EmployeeNumber          
                    ) AS    eg2 ON eg.EmployeeNumber = eg2.EmployeeNumber AND eg.[DateStandard] = eg2.[DateStandard] 
        ) AS eg ON eg.EmployeeNumber = e.EmployeeNumber
)
like image 468
Vahid Jafari Avatar asked May 02 '16 05:05

Vahid Jafari


1 Answers

I think there is no way to change EF query generating strategy. I create a view in my model and add its relation exactly same as Employee table and use it instead.

like image 173
Vahid Jafari Avatar answered Oct 23 '22 05:10

Vahid Jafari