English 中文(简体)
B. 实体框架法
原标题:Entity Framework Code First associations/FK issues and assumptions/defaults

I am very confused by the way Entity Framework is able to pick up on relationships between entities。 I have a few questions on this。

在简单的测试申请中,我有一份人员表,一份说明表和一张照片资产表。

  1. There are many pictures, each is owned by a person (a person can own more than one)。
  2. There are many notes, each is owned by a person (a person can own more than one)。
  3. and finally a person has a logo which is a picture。

    public class Person
    {
        public int ID { get; set; }

        public string name { get; set; }

        public Picture logo { get; set; }
    }

    public class Note
    {

        public int ID { get; set; }

        public string Text { get; set; }

        public Person Owner { get; set; }
    }


 public class Picture
    {

        public int ID { get; set; }

        public string Path { get; set; }

        public Person Owner { get; set; }
    }

When I try to run, I get the error "Unable to determine the principal end of an association between the types 。。。。"。

(If I drop the Person。logo field, compile/run, then manually add it in to SQL, along with the FK relationship, it works 100% as expected。。。 I just can t seem to work out how to set this from EF itself)。

Can you help with the error? I have read quite a few answers here, but, I just can t seem to adapt it to fix my error。

However, now I have a one to many and a many to one (I don t think this is classed as many to many?), I just don t understand how to create people objects, where a FK is non nullable and the FK doesn t exist yet。

A solution I found, which I really don t like is to make the person。picture column nullable, then create a person, followed by creating a picture, then assign a picture to the person object。。。 but, ideally I don t want it nullable。 There should always be a picture。

问题回答

Old answer assuming your 1:1 relation:

Here are two ways to achieve this, one way is to remove the cross reference navigation by applying 1:N.

    public class Person
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public virtual Picture Logo { get; set; }
    }

    public class Note
    {
        public int ID { get; set; }
        public string Text { get; set; }
    }


    public class Picture
    {
        public int ID { get; set; }
        public string Path { get; set; }
    }

这是一种真正廉价的解决办法,你可能不想比人多出更多的笔记或照片。

So, use Data Annotations to instruct what the foreign key is, this will keep navigation and 1:1.

    public class Person
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public virtual Picture Logo { get; set; }
    }

    public class Note
    {
        [Key, ForeignKey("Person")]
        public int OwnerID { get; set; }
        public string Text { get; set; }
        public virtual Person Owner { get; set; }
    }


    public class Picture
    {
        [Key, ForeignKey("Person")]
        public virtual int OwnerId { get; set; }
        public string Path { get; set; }
        public virtual Person Owner { get; set; }
    }

如你所知,由于1:1的关系,照片和笔记将使用同样的身份证。 如果您的钥匙没有命名为ID,你需要增加一个KeyAttribute,在这种情况下,我们还要加上

请指出您应使用<代码>虚拟。 因此,如果你只想人的名字,你就很可能不希望数据库查询电影信息。

标明为virtual的协会特性将按违约加以重载。 这意味着,如果你找回一个产品实体,其类别信息将无法从数据库中检索,直到你获得其类别财产(或者除非你明确表明,在你写你的LINQ问询时,应当检索该类数据以检索产品物体)。

- Scott Gu - Using EF Code First with an existing database


New answer regarding your clarification:

Bulding further on the Foreign Keys by going back to a 1:N structure with ICollection<T>; once you obtain your person like var boss = Person.Find(BossID) you can then access boss.Pictures which will have the various pictures. You can also assign boss.Logo to be one of those pictures.

    public class Person
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public virtual Picture Logo { get; set; }
        public ICollection<Picture> Pictures { get; set; }
        public ICollection<Note> Notes { get; set; }
    }

    public class Note
    {
        public int ID { get; set; }
        [ForeignKey("Person")]
        public int OwnerID { get; set; }
        public string Text { get; set; }
        public virtual Person Owner { get; set; }
    }


    public class Picture
    {
        public int ID { get; set; }
        [ForeignKey("Person")]
        public virtual int OwnerId { get; set; }
        public string Path { get; set; }
        public virtual Person Owner { get; set; }
    }

You might be interested in hinting your data members using DataAnnotations as well as taking a look to the current Conventions for Code First.

public class Person 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 
    public virtual Picture Logo { get; set; } 
    public ICollection<Picture> Pictures { get; set; } 
    public ICollection<Note> Notes { get; set; } 
} 

public class Note 
{ 
    public int ID { get; set; } 

    public int OwnerID { get; set; } 
    public string Text { get; set; } 
    [ForeignKey("OwnerId")] 
    public virtual Person Owner { get; set; } 
} 


public class Picture 
{ 
    public int ID { get; set; } 

    public virtual int OwnerId { get; set; } 
    public string Path { get; set; } 
    [ForeignKey("OwnerId")] 
    public virtual Person Owner { get; set; } 
} 

The above code is right, after trying the wrong code several times, I got the right code.

Hope it is usefull for you.





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签