Entity Framework 6 Recipes 2nd Edition (11-4), recipes11-4
11-4. Call another "model definition" function in the "model definition" Function
Problem
You want to use a "model definition" function to implement another "model definition" function.
Solution
Assume that we have a company partnership with their structural model, as shown in Figure 11-4:
Figure 11-4.A model representing the associate types in a company together with the reporting association
In our virtual company, team members is managed by a team leader. Team leaders is managed by project Managers. Supervisors manages project managers.
If we want to return all the team members they manage from a given project manager or supervisor, we will need to get the team members through the project manager and team leaders. to hide the complexity of navigation through these layers, we can create a "model definition" function to access these navigation attributes more simply and directly:
1. In solution resource management, right-click the. edmx file and open the method development XML editor.
2. Insert the code in Listing 11-7 to the <Schema> label of the concept layer, and define the function.
Listing 11-7.Model-Defined Functions for Navigating the Associate Hierarchy
<Function Name = "GetProjectManager" ReturnType = "EFRecipesModel1104.ProjectManager">
<Parameter Name = "teammember" Type = "EFRecipesModel1104.TeamMember"/>
<DefiningExpression>
Treat (teammember. Manager. Manager as EFRecipesModel1104.ProjectManager)
</DefiningExpression>
</Function>
<Function Name = "GetSupervisor" ReturnType = "EFRecipesModel1104.Supervisor">
<Parameter Name = "teammember" Type = "EFRecipesModel1104.TeamMember"/>
<DefiningExpression>
Treat (EFRecipesModel1104.GetProjectManager (teammember). Manager
EFRecipesModel1104.Supervisor)
</DefiningExpression>
</Function>
3. insert and query the Model Code, as shown in Listing 11-8:
Listing 11-8.Using Both eSQL and LINQ to Query the Model
Class Program
{
Static void Main (string [] args)
{
RunExample ();
Console. WriteLine ("\ nPress any key to exit ...");
Console. ReadKey ();
}
Static void RunExample ()
{
Using (var context = new EFRecipesEntities1104 ())
{
Context. Database. ExecuteSqlCommand ("delete from chapter11.associate ");
Var john = new Supervisor {Name = "John Smith "};
Var steve = new Supervisor {Name = "Steve Johnson "};
Var jill = new ProjectManager
{
Name = "Jill Masterson ",
Manager = john
};
Var karen = new ProjectManager
{
Name = "Karen Carns ",
Manager = steve
};
Var bob = new TeamLead {Name = "Bob Richard", Manager = karen };
Var tom = new TeamLead {Name = "Tom Landers", Manager = jill };
Var nancy = new TeamMember {Name = "Nancy Jones", Manager = tom };
Var stacy = new TeamMember
{
Name = "Stacy Rutgers ",
Manager = bob
};
Context. Associates. Add (john );
Context. Associates. Add (steve );
Context. SaveChanges ();
}
Using (var context = new EFRecipesEntities1104 ())
{
Console. WriteLine ("Using eSQL ...");
Var emps = context. Associates. OfType <TeamMember> ()
//: This where is the form of the downloaded source code, but it is not eSQL.
. Where (q => q. Manager. Name = "Jill Masterson" | q. Manager. Name = "Steve Johnson ");
// Note: the code in this where book is similar to eSQL, but the reload in the form of Where cannot be found. It may be known in an extension package!
//. Where (@ "EFRecipesModel1104.GetProjectManager (it). Name = @ projectManager |
// EFRecipesModel. GetSupervisor (it). Name = @ supervisor ",
// New ObjectParameter ("projectManager", "Jill Masterson "),
// New ObjectParameter ("supervisor", "Steve Johnson "));
Console. WriteLine ("Team members that report up to either ");
Console. WriteLine ("Project Manager Jill Masterson ");
Console. WriteLine ("or Supervisor Steve Johnson ");
Foreach (var emp in emps)
{
Console. WriteLine ("\ tAssociate: {0}", emp. Name );
}
}
Using (var context = new EFRecipesEntities1104 ())
{
Console. WriteLine ();
Console. WriteLine ("Using LINQ ...");
Var emps = from e in context. Associates. OfType <TeamMember> ()
Where MyFunctions. GetProjectManager (e). Name =
"Jill Masterson" |
MyFunctions. GetSupervisor (e). Name = "Steve Johnson"
Select e;
Console. WriteLine ("Team members that report up to either ");
Console. WriteLine ("Project Manager Jill Masterson ");
Console. WriteLine ("or Supervisor Steve Johnson ");
Foreach (var emp in emps)
{
Console. WriteLine ("\ tAssociate: {0}", emp. Name );
}
}
}
}
Public class MyFunctions
{
[EdmFunction ("EFRecipesModel1104", "GetProjectManager")]
Public static ProjectManager GetProjectManager (TeamMember member)
{
Throw new NotSupportedException ("Direct CILS not supported .");
}
[EdmFunction ("EFRecipesModel1104", "GetSupervisor")]
Public static Supervisor GetSupervisor (TeamMember member)
{
Throw new NotSupportedException ("Direct CILS not supported .");
}
}
The above Listing 11-8 code output is as follows:
Using eSQL...
Team members that report up to either
Project Manager Jill Masterson
Or Supervisor Steve Johnson
Associate: Nancy Jones
Associate: Stacy Rutgers
Using LINQ...
Team members that report up to either
Project Manager Jill Masterson
Or Supervisor Steve Johnson
Associate: Nancy Jones
Associate: Stacy Rutgers
How does it work?
In the GetSupervisor () function shown in Listing 11-7, we need to perform three-step navigation for the Manager attribute. navigate from TeamMember to TeamLead for the first time, from TeamLead to ProjectManager for the second time, and from ProjectManager to Supervisor for the last time. in Listing 11-7, we also define the GetProjectManager () function, so we can use this function to simplify the GetSupervisor () function.
We use the eSQL treat () operator to convert a company partner instance to their correct type (ProjectManager or Supervisor ). if you do not use this operator, EF raises an exception (you cannot map Associate to ProjectManager or Supervisor)
In Listing 11-8, using the GetProjectManager () and GetSupervisor () functions can simplify our code, because it hides all the details of traversing object graphs through the Manager navigation attribute.
Because our function does not return an IQueryable <T>, we do not need to implement runtime methods for the LINQ query, but only need to use their method stubs.
Appendix: script file of the database used in the Creation example