1

I have the following classes (annotated for brevity);

public partial class Device
{
    [Key]
    public int ID { get; set; }
    public virtual Policy MainPolicy { get; set; }
}

   public class Policy
   {
        [Key]
        public override int ID { get; set; }

        [ForeignKey("ID"), Column("deviceid")]
        public virtual Device MainDevice { get; set; }
   }

Now when I try to select from the db using linq (for example from device perspective and try to include policy data).

When I then try to return the serialized result I am getting a Self referencing loop detected for the property device and policy.

For example, selecting from the devices perspective;

    var result = _dbset
        .Include(x => x.Policy)
        .Where(predicate);

    return result.ToList();

I then go to look to filter and return the results in my webapi method as follows;

    var filtered = from x in results
                   select new
                   {
                       ID = x.ID,
                       PolicyNumber = x.MainPolicy.Number,
                       Created = x.CreatedDate
                   };

    return Ok(filtered);

As far as I was aware the ForeignKey attribute should fix this? i.e. in the above code by decorating the MainDevice with the ForeignKey("ID") this should tell EF which way around the relationship is?

I'd rather fix and understand this than simply adding the json ignore loop if possible.

6
  • You go on and on about EntityFramework and then at the end throw a curveball with something about json. Your question is very unclear. Commented Sep 1, 2015 at 5:41
  • Sorry Sam, basically the issue I am having is that policy references a device and device refences a policy (from a linq perspective I would like to be able relate to each) heres an example of my link for getting the results; var result = _dbset .Include(x => x.Policy) .AsExpandable() .Where(predicate); You are correct the issue comes when I try to serialize and return the result. As it is getting stuck in a loop as I want to include (in this case) some of the policy variables in the retun from the device perspective. Commented Sep 1, 2015 at 5:46
  • That still does not explain what json has to do with anything. Commented Sep 1, 2015 at 5:47
  • 1
    Sam is right - this has nothing to do with JSON. If you're trying to serialise these objects, that's again, not related to ForeignKey or any of the entity framework configuration. Commented Sep 1, 2015 at 5:47
  • Rob/Sam, Ok I thought that the ForeignKey attribute told ef which way around the entity was working so that it would stop this loop am i wrong? (I apologise for not being clear). If the EF code looks fine how then can I drill down using linq to get when both classes reference each other? (I assume this is quite a common approach?) Commented Sep 1, 2015 at 5:51

2 Answers 2

3

Ignoring the stuff about JSON for now, your definition is incorrect

[ForeignKey("ID"), Column("deviceid")]
public virtual Device MainDevice { get; set; }

This is telling EntityFramework to create a column named 'ID' with a foreign key to the MainDevice table. Then you're also asking to name the column deviceid. I'm not even sure if EF will even allow you to do that on a non-primitive type.

Anyway, assuming your model is a 1-1 relationship, you should do this:

public partial class Device
{
    [Key]
    public int ID { get; set; }

    public int MainPolicyId { get; set; }

    [ForeignKey("MainPolicyId")]
    public virtual Policy MainPolicy { get; set; }
}

public class Policy
{
    [Key]
    public override int ID { get; set; }

    public int MainDeviceId { get; set; }

    [ForeignKey("MainDeviceId")]
    public virtual Device MainDevice { get; set; }
}
Sign up to request clarification or add additional context in comments.

4 Comments

Hi Rob, thanks for this. So if I need the column for MainDeviceId to be "deviceid" (this table is existing in the db). The I can just decorate the property MainDeviceId with [Column"deviceid"]?
@user3545438 If you want that, then rename public int MainDeviceId { get; set; } to public int deviceid{ get; set; } and then change the foreign key to [ForeignKey("deviceid")]
Hi Rob, thanks for the reply. I get the following error message when trying to create the migration The ForeignKeyAttribute on property 'Device' on type 'Policy' is not valid. The foreign key name 'deviceid' was not found on the dependent type 'Device'. The Name value should be a comma separated list of foreign key property names.?
just for more info I currently have the following in Policy; public int deviceid { get; set; } [ForeignKey("deviceid")] public virtual Device Device { get; set; } and in device I have; public int PolicyId { get; set; } [ForeignKey("PolicyId")] public virtual InsurancePolicy Policy { get; set; }
1

I think that you're using ForeignKey attribute wrong. With this attribute you can override default foreign key name.

Please, read this article about foreign keys

So, I guess in your situation you don't need to use this attribute, just make your model look like this:

public partial class Device
{
    [Key]
    public int ID { get; set; }

    public int MainPolicyId { get; set; }

    public virtual Policy MainPolicy { get; set; }
}

public class Policy
{
   [Key]
   public override int ID { get; set; }

   public int MainDeviceId { get; set; }

   public virtual Device MainDevice { get; set; }
}

You can use ForeignKey attribute if you want to use different names for you FKs. For example:

public partial class Device
{
    [Key]
    public int ID { get; set; }

    [ForeignKey("MainPolicy")]
    public int CurrentPolicyId { get; set; }

    public virtual Policy MainPolicy { get; set; }
}

Or vice versa:

public partial class Device
{
    [Key]
    public int ID { get; set; }

    public int MainPolicyId { get; set; }

    [ForeignKey("MainPolicyId")]
    public virtual Policy SomePolicy { get; set; }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.