Wednesday, April 23, 2008

Daniel Simmons commented on the next beta of EF where the team has worked with the WCF team to allow for better serialization (in an interoperable way) of complete graphs and relations. I'm very excited to hear that, but as Julie Lerman pointed out: it's also kind of frustrating for me. ;-)

As you know, I have 3 different pieces of technology that help make the possibility of n-tier disconnected scenario easy.

One of those pieces is the circular serializer, that was created to change the way WCF serializes circular references. However, it has grown to also support 'original' values.

My current plan is as follows:
I will wait to see how WCF serializes entity graphs in the next beta. I expect to see that my circular serializer is no longer necessary. Hopefully I will be able to remove it all together.
What will still be necessary though is getting the original values across the wire. So, I'll probably generate those properties inside of the classes themselves, negating the use of a surrogate serializer. Then, on the client, you will just be able to use your objects like before, and on the server you would notify the objectgraph of the need to fill the original values just before you return them. This might work out very well.

The use of a surrogate is actually what is stopping me from targeting Silverlight, so with a little luck, the changes in the next version will enable the use of Silverlight as well. I'm looking forward to it!

Wednesday, April 23, 2008 11:12:39 AM (Romance Standard Time, UTC+01:00)  #    Comments [9]  |  Trackback
 Wednesday, April 16, 2008

I just finished a small sample application that illustrates a client/server application using Entity Framework on the server and just regular objects on the client. The client has custom changetracking and the server is able to attach the graph to a context again. Source can be found at the efcontrib page, and I guess I'm almost ready to do a proper release!

[I used Prism to build the client in a Model View Controller approach. It was a fun exercise and I'm looking forward to seeing that project released.]

The application manages employees and allows for setting a 'teamleader' on an employee: think of 'is managed by'. I thought it would be cool to send that over the wire.

Here is a screenshot of the main view of the application:

image

As you can see, you can 'choose' an employee. When you press that button, you will see another screen where you can enter a lastname. It will fill a grid with employees matching that criteria and allows you to choose from that list.
It is also allowed to 'add an employee'. There are actually 3 types of employees you can add: Mort, Elvis and Einstein.

On the row of teamleader, you can again press the 'choose' button, which will allow you to set a relation between the employee you are editing and another employee.

On the server, there are a few methods like this:

  0   public List<Employee> GetEmployees(string lastNameBeginsWith)
  1   {
  2    using (InheritanceTypeContext context = new InheritanceTypeContext())
  3    {
  4
  5     List<Employee> employees = (from e in context.Person.OfType<Employee>().Include("TeamLeader").Include("TeamMembers")
  6       where e.Lastname.StartsWith(lastNameBeginsWith)
  7       select e).ToList();
  8
  9    
  10     employees.ForEach(p => context.PrepareForSerialization(p)) ;
  11     return employees;
  12    }
  13   }
  14

 

You can see me taking care to call the 'prepareForSerialization' on each graph that I'm returning on line 10.

The client can just use these objects like normal.

 

I'll look into delving into it a bit with a screencast soon.

Wednesday, April 16, 2008 2:55:10 PM (Romance Standard Time, UTC+01:00)  #    Comments [6]  |  Trackback

I first wanted to focus on the other aspects of EFContrib, but I finally sat down and finished the last missing piece of EFContrib: full inheritance support for both the server bits and the client bits.

Most work was in the serialization actually, since the surrogate classes need to now also serialize the properties of base types.

I'm working on a sample right now that will show off the system in WPF. But you can check out some of the code in the test project.
This is the domain I'm using:

image

In the following code I'm using it.

  0    using (InheritanceTypeConnection context = new InheritanceTypeConnection())
  1    {
  2     var persons = from p in context.Person
  3          select p;
  4     foreach (Person p in persons)
  5      context.DeleteObject(p);
  6
  7     context.SaveChanges();
  8    }
  9
  10    string MsgOnWire = String.Empty;
  11    int id;
  12    using (InheritanceTypeConnection context = new InheritanceTypeConnection())
  13    {
  14
  15     Einstein lead = new Einstein { Firstname = "Bill", Lastname = "G" };
  16     context.AddToPerson(lead);
  17
  18     Mort e1 = new Mort { Firstname = "Ruurd", Lastname = "Boeke", Language = "C#", EF=true, WCF=true, WF= true, WPF=true, TeamLeader=lead };
  19     context.AddToPerson(e1);
  20
  21     Elvis e2 = new Elvis { Firstname = "Elvis", Lastname = "Presley", Language = "Java", EF = false, WCF = true, WF = false, WPF = true, TeamLeader = lead };
  22     context.AddToPerson(e2);
  23
  24     context.SaveChanges();
  25     id = e1.PersonID;
  26
  27     MsgOnWire = context.Serialize(e1);  // we'll take mort as the graphroot (no importance)
  28    }
  29
  30    // deserialize
  31    MortClient mClient = MsgOnWire.DeserializeForClient<MortClient>();
  32    mClient.Firstname = "changedAt" + DateTime.Now.ToString();
  33    string nameToCheck = mClient.Firstname;
  34    mClient.EF = false; // mort tends to forget skills
  35
  36    EmployeeClient teamlead = mClient.TeamLeader;
  37
  38    // elvis is a free soul, he can not be managed.
  39    ElvisClient eClient = (ElvisClient) mClient.TeamLeader.TeamMembers.Last();
  40    mClient.TeamLeader.TeamMembers.Remove(eClient);
  41    eClient.TeamLeader = null;
  42
  43    // always add more einsteins in the mix
  44    EinsteinClient einClient = new EinsteinClient { EF = true, WCF = true, WF = false, WPF = false, TeamLeader = teamlead, Firstname = "Albert", Language = "C#", Lastname = "Einstein" };
  45    teamlead.TeamMembers.Add(einClient);
  46
  47
  48    // serialize
  49    MsgOnWire = mClient.SerializeForClient();
  50
  51
  52    using (InheritanceTypeConnection context = new InheritanceTypeConnection())
  53    {
  54
  55     // deserialize
  56     Mort m = context.Deserialize<Mort>(MsgOnWire);
  57
  58     context.SaveChanges();
  59    }
  60

Lines 31 to 41 represent the client. For testing purposes I created a copy of the domain with the suffix Client. In normal usage this would obviously not be necessary.
The client remembers all the original values, which allows the server to build up an efficient graph when it is time to attach.

Wednesday, April 16, 2008 11:18:32 AM (Romance Standard Time, UTC+01:00)  #    Comments [0]  |  Trackback
 Tuesday, April 15, 2008

I'm building a small sample for EFContrib, and thought it would be cool to use the new MVC framework 'Prism' for it. Prism is a new framework currently under development by the patterns and practices group. It is not feature complete and everything might change in the next drop. But, well, it's fun to see such a framework develop and how best to understand it, than by building something simple with it!

I'm trying to do something fairly basic: I have a view that has a button on it. If the button is pressed, a form should popup where we can search for employees. When the search is over, the result should be accessible by my controller.
At the same time though, I know that I'm going to have a detail screen as well with the same button on it. Here the button chooses a teamleader for the employee.

I want to define the command once, but need my controllers to behave differently. It's quite possible that I would be better off just creating two commands (one for the detail screen and one for the employee screen). You could argue that they perform different actions: choose an employee versus choose a teamleader.
But I don't swing that way and I feel it should be possible to have the same command on a lot of buttons and let the appropriate controller deal with it.

In the prism project are a few base classes for commands: the DelegateCommand and also the ActiveAwareDispatchCommand. As far as I can see, they allow a command to be hooked up by multiple views and allow controller to register their interest in them.
I created a static class with my 'ChooseEmployee' command:

 

    public static class EmployeeChooserCommands
    {
        public static ActiveAwareMultiDispatchCommand ChooseEmployee = new ActiveAwareMultiDispatchCommand();
      }

Now, my views couple their buttons to this command in the regular way.

In my definition of MVC a controller is responsible for the logic and thus handles this command.

        protected ActiveAwareDelegateCommand chooseEmployeeCommand;

It defines it's own command and in the ctor hooks it up:

            chooseEmployeeCommand = new ActiveAwareDelegateCommand(Choose, CanChoose);
            // register this instance on the global
            EmployeeChooserCommands.ChooseEmployee.RegisterCommand(chooseEmployeeCommand);

The last line will make this controller react to executions of the command by every source.

This is the pattern that I see in the current Prism reference implementation project.

The fun thing about the ActiveAwareDelegate is the way you can set it as Active and not-Active. If it is not active, it will not be queried for canExecute information and its execute delegate will not be called.

So, what I did, was to let my views implement the IActiveAware interface and throw an event when they lose or get focus. The corresponding controllers react to it in this way:

        void view_IsActiveChanged(object sender, EventArgs e)
        {
            chooseEmployeeCommand.IsActive = view.IsActive;
          }

Setting the command to only be active when the view is active.
Downside here is that if one view is active, it gets to decide on the canExecute result, but all buttons in all views will react to it: clearly not what we want.

So, I feel I'm on the wrong track here. I really miss being able to set some sort of 'affinity' to the RegisterCommand method. I would like to let that method know I'm interested in commands where the source is equal to my view. But then again, maybe I should just create different commands :-)

Tuesday, April 15, 2008 5:50:12 PM (Romance Standard Time, UTC+01:00)  #    Comments [14]  |  Trackback