如何在实体框架的FluentAPI /数据注释中定义外键可选关系? [英] How do I define Foreign Key Optional Relationships in FluentAPI/Data Annotations with the Entity Framework?

查看:1075
本文介绍了如何在实体框架的FluentAPI /数据注释中定义外键可选关系?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  public class Posts 
{

[Key]
[必需]
public int ID {get;组;

[必需]
public string TypeOfPost {get;组; }

public int PollID {get;组; }
public virtual Poll Poll {get;组; }

public int PostID {get;组; }
public virtual Post Post {get;组; }

}

基本上,我不知道是否有更好的方式,但是,我有一个帖子列表,人们可以选择是否是投票发布,由于Entity Framework不适用于Enums,所以我只将它存储为 TypeOfPost 中的字符串,然后在应用程序中以编程方式查询投票或邮寄根据 TypeOfPost 的值。



我不认为有设置只有一个必需或类似的,所以,我处理应用程序中的所有检查和东西。 (如果有人知道更好的方法,请说!)



无论如何,问题是,我可以通过进入SQL Management Studio并手动编辑允许空值的模式 - 但是,我无法解决如何在FluentAPI中执行此操作,并且需要一些帮助。



我已经尝试了以下两个:

  modelBuilder.Entity< Post>()
.HasOptional(x => x.Poll).WithOptionalDependent ();

modelBuilder.Entity< Post>()
.HasOptional(x => x.Poll).WithOptionalPrincipal();

第一个似乎在数据库中创建一个允许null的附加列,第二个列



我相信第一个是我需要的,但是我需要结合[ForeignKey]在发布类。如果我在这里是正确的,[ForeignKey]是否会继续使用虚拟财产或财产的ID?



另外, WithOptionalDependent WithOptionalPrincipal ? - 我已经阅读了MSDN,但是我真的不明白这个区别。

解决方案

我可能会尝试创建两个一对一的关系为可选:必需,因为投票 必须引用帖子发布必须引用帖子

  modelBuilder.Entity< Posts>()
.HasOptional(x => x.Post)
.WithRequired();

modelBuilder.Entity< Posts>()
.HasOptional(x => x.Poll)
.WithRequired();

这使得职位自动将关系和发布投票依赖关系。主体具有关系中的主键,依赖外键同时也是主键在 Post / 投票表,因为它是一对一的关系。只有在一对多关系中,您将有一个单独的外键列。对于一对一的关系,您还必须删除外键列 PostId PollId ,因为帖子通过其主键指向 Post 投票。 p>

在您的模型中似乎适合的替代方法是继承映射。那么模型将如下所示:

  public abstract class BasePost //你以前的帖子类
{
public int ID {get;组; }
public string UserName {get;组;
}

public class Post:BasePost
{
public string Text {get;组; }
// Post class的其他属性
}

public class Poll:BasePost
{
// Poll类的属性
}

您不需要 TypeOfPost 然后再来,因为你可以使用 OfType LINQ运算符过滤两个具体类型,例如:

  var x = context.BasePosts.OfType< Post>()
.Where(p => p.UserName ==Jim)
.ToList();

这将选择特定用户的所有帖子,而不是投票。



您必须决定要使用哪种继承映射 - TPH,TPT或TPC



编辑



要获得一对多关系,您可以在Fluent API中指定以下映射: p>

  modelBuilder.Entity< Posts>()
.HasOptional(x => x.Post)
。 WithMany()
.HasForeignKey(x => x.PostID);

modelBuilder.Entity< Posts>()
.HasOptional(x => x.Poll)
.WithMany()
.HasForeignKey(x => x.PollID);

外键属性必须为空( int?)为您已经找到。因为您的外键属性的命名遵循命名约定EF用于映射,您可以完全省略Fluent映射。只有您有非常规名称(如 PostFK 或某些东西)才需要。然后,您也可以使用数据注释( [ForeignKey(...)] 属性)而不是Fluent API。


I have a (sample) application with the following code:

public class Posts
{

    [Key]
    [Required]
    public int ID { get; set; }

    [Required]
    public string TypeOfPost { get; set; }

    public int PollID { get; set; }
    public virtual Poll Poll { get; set; }

    public int PostID { get; set; }
    public virtual Post Post { get; set; }

}

Basically, I don't know if there is a better way of doing this, but, I have a list of Posts, and, people can choose if it is a Poll or a Post, As Entity Framework doesn't work with Enums, I just store it as a string in TypeOfPost and then in the application, I programmatically query either Poll or Post based on the value of TypeOfPost.

I don't think there is anyway of setting "Only one required" or similar, so, I handle all the checking and stuff in the application. (If anyone knows a better way, please say!).

Anyway, the problem is, I can get this working fine by going in to SQL Management Studio and manually editing the schema to allow nulls - but, I just can't work out how to do this in the FluentAPI, and need some help.

I have tried both of the following:

modelBuilder.Entity<Post>()
    .HasOptional(x => x.Poll).WithOptionalDependent();

modelBuilder.Entity<Post>()
    .HasOptional(x => x.Poll).WithOptionalPrincipal();

The first one seems to create an additional column in the database that allows nulls, and the second one doesn't appear to do anything.

I believe the first one is the one I need, but, I need to use it in combination with [ForeignKey] in the Post Class. If I am correct here, Should the [ForeignKey] go on the virtual property, or the ID of the property?

In addition, what is the actual difference between WithOptionalDependent and WithOptionalPrincipal? - I have read on MSDN, but, I really do not understand the difference.

解决方案

I would probably try to create the two one-to-one relationships as optional:required because a Poll must have a reference to Posts and a Post also must have a reference to Posts:

modelBuilder.Entity<Posts>()
    .HasOptional(x => x.Post)
    .WithRequired();

modelBuilder.Entity<Posts>()
    .HasOptional(x => x.Poll)
    .WithRequired();

This makes Posts automatically the principal in the relationship and Post or Poll the dependent. The principal has the primary key in the relationship, the dependent the foreign key which is also the primary key at the same time in Post/Poll table because it is a one-to-one relationship. Only in a one-to-many relationship you would have a separate column for the foreign key. For a one-to-one relationship you also have to remove the foreign key columns PostId and PollId because Posts refers through its primary key to the Post and Poll.

An alternative approach which seems to be appropriate in your model is inheritance mapping. Then the model would look like this:

public abstract class BasePost  // your former Posts class
{
    public int ID { get; set; }
    public string UserName { get; set; }
}

public class Post : BasePost
{
    public string Text { get; set; }
    // other properties of the Post class
}

public class Poll : BasePost
{
    // properties of the Poll class
}

You don't need the TypeOfPost then anymore because you can filter the two concrete types using the OfType LINQ operator, for example:

var x = context.BasePosts.OfType<Post>()
    .Where(p => p.UserName == "Jim")
    .ToList();

This would select all posts of a particular user but not the polls.

You have to decide then which kind of inheritance mapping you want to use - TPH, TPT or TPC.

Edit

To get a one-to-many relationship you can specify the following mapping in Fluent API:

modelBuilder.Entity<Posts>()
    .HasOptional(x => x.Post)
    .WithMany()
    .HasForeignKey(x => x.PostID);

modelBuilder.Entity<Posts>()
    .HasOptional(x => x.Poll)
    .WithMany()
    .HasForeignKey(x => x.PollID);

The foreign key properties must be nullable (int?) for this as you already found. Because the naming of your foreign key properties follows the naming convention EF uses for mapping you can omit the Fluent mapping altogether. It would only be required if you had unconventional names (like PostFK or something). You could then also use data annotations ([ForeignKey(...)] attribute) instead of Fluent API.

这篇关于如何在实体框架的FluentAPI /数据注释中定义外键可选关系?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆