locked
Lookup ComboBox RRS feed

  • Question

  • Hi

    Thought i had this "EF 4.1 Code First" Model on my WCF Data Service and i'm using "WCF Data Services Mar 2011 CTP2",

      public class City
      {
        public int Code { get; set; }
        public string Name { get; set; }
    
        public City()
        {
        }
    
        public City(int code, string name)
        {
          Code = code;
          Name = name;
        }
      }
    
    
      public class Person
      {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int BirthPlaceCode { get; set; }
        public City BirthPlace { get; set; }
      }
    
    
      public class CityTypeConfiguration : EntityTypeConfiguration<City>
      {
        public CityTypeConfiguration()
        {
          HasKey(t => t.Code);
          Property(t => t.Name).HasMaxLength(20);
        }
      }
    
    
      public class PersonTypeConfiguration : EntityTypeConfiguration<Person>
      {
        public PersonTypeConfiguration()
        {
          HasKey(t => t.Id);
          Property(t => t.FirstName).HasMaxLength(20);
          Property(t => t.LastName).HasMaxLength(30);
          HasOptional(t => t.BirthPlace).WithMany().HasForeignKey(f => f.BirthPlaceCode);
        }
      }
    
    
      public class EmployeeContext : DbContext
      {
        public DbSet<City> Cities { get; set; }
        public DbSet<Person> People { get; set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
          base.OnModelCreating(modelBuilder);
          modelBuilder.Configurations.Add(new CityTypeConfiguration());
          modelBuilder.Configurations.Add(new PersonTypeConfiguration());
        }
      }
    
    

    and this is my WCF Data Service

     

      public class EmployeeDataService : DataService<EmployeeContext>
      {
        public static void InitializeService(DataServiceConfiguration config)
        {
          config.SetEntitySetAccessRule("*", EntitySetRights.All);
          config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
        }
      }
    
    

    now in my WPF Client Application i have Simple DataGrid with a Lookup ComboBox to Cities in it, that allow user to change Selected Person Birth Place, when i'm using EmployeeContext directly, changing person.BirthPlaceCode cause changing person.BirthPlace automaticaly, but when i'm using WCF Data Service reference, this not work automatically. so i want to ask what is problem and what should  i do ? is it my mistake or i should do something manually (if so, what is best practice)?

    Thanks

     

     

     

    Monday, June 13, 2011 1:07 PM

All replies

  • Hi,

    The DataServiceContext class (the Data-Services equivalent of DbContext or ObjectContext) does not do automatic property fixup based on foreign keys. In fact, it largely does not understand foreign keys, and uses the much looser notion of 'links'. Either way, updating a property when another one is updated is something you will need to do either manually in the WPF applications events or in the proxy classes that were originally generated by 'Add Service Reference'. We are looking at ways of making the code-gen experience more extensible, but for now the code-gen does not provide this functionality.

     


    Matt Meehan (WCF Data Services / OData)
    Monday, June 13, 2011 5:11 PM
    Moderator
  • Hi,

     

    Ok, So i should do this manually, but can you help me about what is best practice for doing this in my client side?

     

     

    Tuesday, June 14, 2011 3:45 AM
  • I tried to write a sample using the generated 'On___Changing' partial methods that are part of the partial classes, but found that it would not work because the instances do not automatically know about the current DataServiceContext instance.

    By default, the generated classes implement INotifyPropertyChanged, so you could use that and still get the grid-binding 'for free'.

    Here's what that might look like:


    static void Main(string[] args)
    {
      var ctx = new DataServiceContext(new Uri("http://localhost/MyService.svc/"));
    
      ctx.ReadingEntity +=
        (sender, eventArgs) =>
        {
          var person = eventArgs.Entity as Person;
          if (person != null)
          {
            AddPersonPropertyChangedEventHandler(ctx, person);
          }
        };
    
      var newPerson = new Person();
    
      AddPersonPropertyChangedEventHandler(ctx, newPerson);
    }
    
    private static void AddPersonPropertyChangedEventHandler(DataServiceContext ctx, Person person)
    {
      person.PropertyChanged +=
        (sender, eventArgs) =>
        {
          if (eventArgs.PropertyName == "BirthPlaceCode")
          {
            // scan the cities already tracked by the context to find the right one
            var city = ctx.Entities.Select(e => e.Entity).OfType<City>().SingleOrDefault(c => c.Code == person.BirthPlaceCode);
            // throw if city is null?
            person.BirthPlace = city;
          }
          else if (eventArgs.PropertyName == "BirthPlace")
          {
            if (person.BirthPlace != null)
            {
              person.BirthPlaceCode = person.BirthPlace.Code;
            }
          }
        };
    }



    Note that the event handler is an instance-level thing, so you need to add it whenever an instance of 'Person' is created.

    You could try to do something similar, as I indicated at the beginning of this post, using the partial On__Changing methods, but you would need some way to see all the available instances of City to find the right one for the navigation property. In general, sharing a context statically is not a good idea because it is not thread-safe.

    I admit this is not ideal, but i don't see a nicer solution at the moment. You could do some of this work in the ComboBox's events instead, if you prefer that.


    Matt Meehan (WCF Data Services / OData)





    Tuesday, June 14, 2011 5:11 PM
    Moderator