0

I am facing following issue: I have ProductOrder class which has ProductId as foreign key to Product class. When I invoke following method:

public IEnumerable<ProductOrder> GetOrders()
{
      return OddzialDb.ProductOrders;
}

Orders are associated with Product so I can write something like this:

OddzialDb.ProductOrders.First().Product.Name;

but when it reaches Client it turns out that there is no association with Product which is null (only ProductId is included). In DbContext I have set

   base.Configuration.ProxyCreationEnabled = false;
   base.Configuration.LazyLoadingEnabled = false;

On the WCF Service side auto-generated by EF ProductOrder class looks as follows:

 public partial class ProductOrder
    {
        public int Id { get; set; }
        public Nullable<int> ProductId { get; set; }
        public int Quantity { get; set; }

        public virtual Product Product { get; set; }
    }

What happens that it looses connections with tables associated by foreign keys?

Maximus
  • 3,458
  • 3
  • 16
  • 27

1 Answers1

0

Make your relationship virtual as in the example:

public class ProductOrder
{
    public int Id { get; set; }
    public virtual Product Product { get; set; }
    public int ProductId { get; set; }
}

By turning your relationship virtual, the Entity Framework will generate a proxy of your ProductOrder class that will contain a reference of the Product.

To make sure it will work, Product also has to contain reference to ProductOrder:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<ProductOrder> ProductOrders { get; set; }
}

Set these variables true on your DbContext:

Configuration.LazyLoadingEnabled = true;
Configuration.ProxyCreationEnabled = true;

On your WCF application, add the following class, which will allow for proxy serialization:

public class ApplyDataContractResolverAttribute : Attribute, IOperationBehavior
{
    public ApplyDataContractResolverAttribute()
    {
    }

    public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
    {
    }

    public void ApplyClientBehavior(OperationDescription description, System.ServiceModel.Dispatcher.ClientOperation proxy)
    {
        DataContractSerializerOperationBehavior dataContractSerializerOperationBehavior =
            description.Behaviors.Find<DataContractSerializerOperationBehavior>();
        dataContractSerializerOperationBehavior.DataContractResolver =
            new ProxyDataContractResolver();
    }

    public void ApplyDispatchBehavior(OperationDescription description, System.ServiceModel.Dispatcher.DispatchOperation dispatch)
    {
        DataContractSerializerOperationBehavior dataContractSerializerOperationBehavior =
            description.Behaviors.Find<DataContractSerializerOperationBehavior>();
        dataContractSerializerOperationBehavior.DataContractResolver =
            new ProxyDataContractResolver();
    }

    public void Validate(OperationDescription description)
    {
        // Do validation.
    }
}

Then on your ServiceContract interfaces you add the DataAnnotation [ApplyDataContractResolver] right among your other annotations such as [OperationContract], above any method signature that returns an entity:

[OperationContract]
[ApplyDataContractResolver]
[FaultContract(typeof(AtcWcfEntryNotFoundException))]
Case GetSingleByCaseNumber(int number);
Alexandre Severino
  • 1,563
  • 1
  • 16
  • 38
  • I have already tried Include and in this case I receive circular reference error. When Client consumes WCF Service it has auto-generated classes like Product etc. – Maximus Jun 04 '15 at 15:48
  • With `WCF` you will be better off with the second approach. I never made it work properly myself the other way. – Alexandre Severino Jun 04 '15 at 15:53
  • As far as WCF Service with EF is concerned, both Product and ProductOrders have reference to each other with virtual keyword. – Maximus Jun 04 '15 at 16:02
  • Still, it will only send all of your relationship over the wire as long as you use **Lazy Loading** AND have all of them completely `serializable`. – Alexandre Severino Jun 04 '15 at 16:04
  • I changed to base.Configuration.LazyLoadingEnabled = true. No upturn detected. – Maximus Jun 04 '15 at 16:09
  • Are all of your entities **completely serializable**? – Alexandre Severino Jun 04 '15 at 16:10
  • What can mark them as not completely serializable? If Product has other fields which are associed with FK for instance ClientId do I need to add them to Include as well? – Maximus Jun 04 '15 at 16:25
  • Look up how to make sure your entity is completely serializable. If you can't serialize your entity, including its dynamically generated proxy, you won't be able to pass it via wire. – Alexandre Severino Jun 04 '15 at 16:35
  • I can pass them separately so I do not think is about ability to serialize. – Maximus Jun 04 '15 at 16:44
  • I was away from my computer so I could not help you properly to solve your problem. Now it should have enough information to help you out. – Alexandre Severino Jun 04 '15 at 20:53