本文介绍了实体框架Fluent API关系映射HasRequired()。WithRequired()在没有Map()的情况下无法正确运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

博客模型

using System.Collections.Generic;

namespace DataLayer
{
    public class Blog
    {
        public int BlogKey { get; set; }
        public string Title { get; set; }
        public string BloggerName { get; set; }
        public virtual Post Post { get; set; }
    }
}

发布模型

using System;
using System.Collections.Generic;

namespace DataLayer
{
    public class Post
    {
        public int PostKey { get; set; }
        public string Title { get; set; }
        public DateTime? DateCreated { get; set; }
        public string Content { get; set; }
        public virtual Blog Blog { get; set; }
    }
}

模型配置

using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;

namespace DataLayer
{
    public class BlogConfiguration : EntityTypeConfiguration<Blog>
    {
        public BlogConfiguration()
        {
            ToTable("Blog", "dbo");
            HasKey(k => k.BlogKey).Property(p=>p.BlogKey).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

// This will allow having null Post for the Blog
            //HasRequired(p => p.Post).WithRequiredPrincipal(p => p.Blog).WillCascadeOnDelete(false);

// This will NOT allow having no Post for the Blog
            HasRequired(p => p.Post).WithRequiredPrincipal(p => p.Blog).Map(m=>m.MapKey("OtherBlogKeyColumn")).WillCascadeOnDelete(false);
        }
    }

    public class PostConfiguration : EntityTypeConfiguration<Post>
    {
        public PostConfiguration()
        {
            ToTable("Post", "dbo");
            HasKey(k => k.PostKey).Property(p=>p.PostKey).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

        }
    }
}

客户

using DataLayer;
using System;

namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            MyDbContext c = new MyDbContext();

            //Works when dependent's foreign key column is mapped to the primary key column(this is by default when Map() is not provided).
            //Doesn't work when foreign key column is mapped to some other column(which is provided by Map())
            Blog blog = new Blog { Title = "world", Post = null, BloggerName = "suyash" };


            //Blog required, Post required
            //Blog blog = new Blog { Title = "work", Post = new Post { Title = "new world post" }, BloggerName = "suyash" };

            c.Blogs.Add(blog);

            c.SaveChanges();

        }
    }
}

我有型号博客 Post 。这里讨论的关系是HasRequired()。WithRequired()。 我希望Blog能够成为负责人,而Post则能够成为依赖人。请参阅博客配置。

I have the models Blog and Post. The relationship to discuss here is HasRequired().WithRequired(). I want Blog to be Principal and Post to be Dependent. Please see the Blog Configuration.

有Required(p => p.Post).WithRequiredPrincipal(p => p.Blog).WillCascadeOnDelete (假); 允许使用以下内容发布空消息博客博客=新博客{标题= world,帖子=空,BloggerName = suyash };

但是, HasRequired(p => p.Post).WithRequiredPrincipal(p => p .Blog).Map(m => m.MapKey( OtherBlogKeyColumn))。WillCascadeOnDelete(false); 没有。

使用Map()进行的配置按预期工作,当我们尝试插入空Post时,它将引发错误。

The configuration with Map() works as expected, it throws an error when we try to insert a null Post.

不是HasRequired()。WithRequired()的全部目的是确保即使未使用Map(),两端也都具有一个值。目前没有Map(),它的工作方式与HasOptional(Blog).WithRequired(Post)一样。

Isn't the whole purpose of HasRequired().WithRequired() is to ensure that both the ends have a value even if Map() was not used. Currently without Map() it works just like HasOptional(Blog).WithRequired(Post).

我想了解这是一个真正的错误还是我在这里错过了什么?

I want to understand is this a genuine error or am i missing something here.

推荐答案

必填≠必填


有需要-WithRequired 组合比实际承诺的要多。

Required ≠ required

The HasRequired - WithRequired combination promises more than it actually does. It allows you to store a sole principle without an accompanying dependent.

在关系数据库中(至少在我所知道的实现中),无法在不同的表中存储两行。 ;同时 (即作为原子操作)。因此,没有办法强制执行相互要求的1:1关联。必须先插入主体实体,然后是从属实体。

In a relational database (at least in the implementations I know of) there is no way to store two rows in different tables "at the same time" (i.e. as an atomic operation). So there is no way to enforce a mutually required 1:1 association. The principle entity has to be inserted first, then the dependent entity.

但是这是否可以防止EF要求建立关联?我认为像其他验证一样,在保存更改之前可以验证需求。在我看来,他们本可以强制执行必须-需要

But should this keep EF from making the association required? I think it should be possible to validate the requirements before saving changes, as other validations do. In my opinion they could have enforced HasRequired - WithRequired to be really required. But they didn't.

如果我们有这两个简单的类...

If we have these two simple classes...

public class Principal
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual Dependent Dependent { get; set; }
}

public class Dependent
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual Principal Principal { get; set; }
}

...映射为...

...mapped as...

modelBuilder.Entity<Principal>()
            .HasRequired(pr => pr.Dependent)
            .WithRequiredPrincipal(dep => dep.Principal);

...我们可以做...

...we can do...

var principle1 = new Principal { Name = "Principal1" };
context.Principals.Add(principle1);
context.SaveChanges();

...并且EF很高兴。

...and EF is happy.

我们可以t 插入 Dependent ,而没有 Principle 。这是因为 Dependent 的主键是从 Principle 的主键复制而来的,同时也是外键。但这是1:0..1,而不是1:1。如果我们将关联映射为...

We can't insert a Dependent without a Principle. That's because the Dependent's primary key is copied from the Principle's and it's a foreign key at the same time. But that's 1:0..1, not 1:1. If we map the association as...

modelBuilder.Entity<Principal>()
            .HasOptional(pr => pr.Dependent)
            .WithRequired(dep => dep.Principal);

...我们得到相同的数据模型。

...we get the same data model.

获得真正必需的 1:1关联的一种方法是 实体分裂 。 是:

One way to get a really required 1:1 association is by entity splitting. A common example is:

modelBuilder.Entity<Department>()
    .Map(m =>
    {
        m.Properties(t => new { t.DepartmentID, t.Name });
        m.ToTable("Department");
    })
    .Map(m =>
    {
        m.Properties(t => new { t.DepartmentID, t.Administrator, t.StartDate, t.Budget });
        m.ToTable("DepartmentDetails");
    });

这还会创建一个具有从属关系的数据模型。 (此处 DepartmentDetails )共享原理的PK并通过FK进行引用。现在,如果没有 DepartmentDetails ,就无法创建部门,因为我们只能创建部门对象, DepartmentDetails 不是类,并且数据库中始终有两条记录。

This also creates a data model with a "Dependent" (here DepartmentDetails) that shares the "Principle"'s PK and refers to it through a FK. Now we can't create a Department without DepartmentDetails because we can only create a Department object, DepartmentDetails isn't a class, and there are always two records in the database.

但是当然,这与在类模型中具有两个实体完全不同。两种型号的用法完全不同。例如,当您查询部门时,部门详细信息将会总是 加入。这是真正的1:1(在数据模型中),但不能替代1:1作为类。

But of course this is completely different from having two entities in the class model. Both models have completely different usages. For one, when you query a Department, DepartmentDetails will always be joined in. So this is genuine 1:1 (in the data model), but not an alternative to 1:1 as classes.

另一种方法是映射 复杂类型 。一个非常简单的例子是:

Another way is mapping a complex type. A very rudimentary example is:

public class Person
{
    public int Id { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public string Street { get; set; }
    public int Number { get; set; }
    public string Town { get; set; }
}

在没有任何映射的情况下,这会创建一个包含 Person Address (EF推断 Address 为复杂类型,因为它没有定义键)。现在我们有两个类,并且没有地址,我们就不能创建 Person (并且反向)。但是现在我们无法从数据库中获取地址。他们有点太依赖了。而且 Address 不是实体,因为它没有身份。这是值类型。再次重申,这是一种替代方法,但完全不同。

Without any mapping this creates one table containing all fields from Person and Address (EF infers Address as a complex type because it has no key defined). Now we have two classes, and we can't create a Person without an address (and reverse). But now we can't fetch Addresses from the database. They're a bit too dependent. And Address is not an entity, because it hasn't got an identity. It's a value type. So again, this is an alternative, kind of, but an entirely different usage.

这篇关于实体框架Fluent API关系映射HasRequired()。WithRequired()在没有Map()的情况下无法正确运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 03:08