简体   繁体   中英

Return request in web method WCF

I have Web service and a method which makes a request to my table 'Customer' with Entity Framework.

I want to return the result of my request :

[WebMethod]
public Customer MyMethod(int id)
{
    Model model = new Model();
    Customer customer = new Customer();

    try
    {
        customer = model.Customer.Where(x => x.Name == id).First();
    }
    catch (Exception ex)
    {
        throw new System.NullReferenceException(ex.Message, ex.InnerException);
    }

    return customer;
}

My Class Customer (generated by EF) :

[Table("Customer")]
public partial class Customer
{
    public int Id { get; set; }

    [StringLength(50)]
    public string Name { get; set; }

    public int? Adress_id { get; set; }

    public virtual Adress Adress { get; set; }
}

Class Adress (generated by EF) :

[Table("Adress")]
public partial class Adress
{
    public Adress()
    {
        Customer = new HashSet<Customer>();
    }

    public int Id { get; set; }

    [Column("Adress")]
    [StringLength(255)]
    public string Adress1 { get; set; }

    [StringLength(50)]
    public string Town { get; set; }

    public virtual ICollection<Customer> Customer{ get; set; }
}

But I have no answer when I call my method with SoapUI. If I delete the property virtual Adress then I have an answer but I need to get back the address also (joint)

Thank you

Because of the virtual properties it's impossible to serialize the models to send them. Your address in customer has references to customers, which has again references to address... That's an infinite loop. Because of this, you can use DTO (Data Transfer Object) classes to transmit the data. For your Customer model it would look like this:

public class CustomerDTO
{
  public int Id { get; set; }
  public string Name { get; set; }
  public int? Adress_id { get; set; }

  public Adress Adress { get; set; }      
}

Before you send it over WCF you have to transform your Customer into CustomerDTO objects. You can even do that in one statement with linq:

var obectToTransfer = db.Customers.Where(c => c.Id == 5)
                                  .Select(c => new CustomerDTO
                                  {
                                     Id = c.Id
                                     ...
                                  }).FirstOrDefault();

If you want to load explicitly a relative property as part of the query, you can do that through Eagerly Loading, which is using Include extension method:

 customer = model.Customer.Include(c=>c.Address).Where(x => x.Name == id).First();

You can also use Explicit Loading:

 customer = model.Customer.Where(x => x.Name == id).First();
 context.Entry(customer).Reference(p => p.Address).Load();

Now I recommend you to check that relationship in your Database. If you are not using Fluent Api to to configure that relationship, then EF doesn't know that Address_id is the FK for that relationship. The foreign key property will be discovered by convention if it is named [Target Type Key Name] , [Target Type Name] + [Target Type Key Name], or [Navigation Property Name] + [Target Type Key Name] . One way to override this convention is using ForeignKey attribute. So, first check the relationship in your DB and after that if you have an Address related to the Customer that you want to load. You should be able to load the Address navigation property using one of the two variants I propose above.

I remove the Keyword virtual in my class customer :

[Table("Customer")]
public partial class Customer
{
    public int Id { get; set; }

    [StringLength(50)]
    public string Name { get; set; }

    public int? Adress_id { get; set; }

    public Adress Adress { get; set; }
}

And I remove the constructor in my class Adress and the property ICollection<Customer> Customer

[Table("Adress")]
public partial class Adress
{
    public int Id { get; set; }

    [Column("Adress")]
    [StringLength(255)]
    public string Adress1 { get; set; }

    [StringLength(50)]
    public string Town { get; set; }
}

And my query : customer = model.Customer.Include("Adress").Where(x => x.Id == 2).First();

It works!

My response :

<a:Adress>
   <a:Adress1>101 Madison Ave</a:Adress1>
   <a:Id>1</a:Id>
   <a:Town>New York</a:Town>
</a:Adress>
<a:AdressId>1</a:AdressId>
<a:Name>John</a:Name>
<a:Id>2</a:Id>

But it's not practical

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM