实体框架6 - 导航属性的主键

时间:2016-11-20 21:48:47

标签: c# entity-framework

Entity Framework 6.1.3使用 Code First 方法,我正在尝试根据this post创建和配置我自己的多对多表。我强烈同意他的意见:我不想遵守这些惯例,因为这限制了我的设计。

看看Code First中的多对多with payload课程:

public class FooBar
{
    [Key, Column(Order = 1)]
    public virtual Foo Foo { get; set; }

    [Key, Column(Order = 2)]
    public virtual Bar Bar { get; set; }

    //some more 'payload' properties
}

我想在不添加标量属性的情况下保持这种方式。所以我想在我的模型中使用这些属性:

public int FooId { get; set; }
public int BarId { get; set; }

如果在Entity Framework 6中有可能将这样的导航属性作为(复合)键,我的问题是具体吗? Most answers这个问题是基于早期版本的Entity Framework,然后就不可能了。所以问题是,现在可能吗?

this answer中提到:

  

您需要以特定方式设置类,以便EF识别   你想要实现的目标。

但是,如果技术上可行,我仍然不清楚。如果是,有人可以在代码中提供如何实现这一目标的样本吗?

3 个答案:

答案 0 :(得分:1)

不能那样做

不仅使用EF 6.X,而且在EF Core中也是如此。这是设计的。如果您不在联结表上定义这些标量属性,EF不知道如何映射关系。我不得不说,这是设计的。不幸的是,你在这里没有任何其他选择。您必须在联结表上包含这些标量属性。

答案 1 :(得分:1)

我希望这对某些人有用。

在搜索引擎上搜索了几个小时之后,我终于在这里做到了。可悲的是,你和我所面临的同样问题都没有答案。我只是不想撤回我的设计选择并创建许多标量类型,就像你在帖子中所说的那样。

我想出了实现基本OOP的解决方案:

// let's assume we would like to have each ObjectModel with
// unique Name and Class properties
// this two data will identify the whole row. (i.e ShadowHawk:Bow)

class ObjectModel {

   public string Name { get; set; }
   public ItemClass ItemClass { get; set; }
   ...
   public MagicAttr[] Attributes { get; set; }
   ...
}

class ObjectEntity : ObjectModel {

   public int Class_id
   ...
   other foreign keys as primary keys
}

使用这种方法,我的ObjectModel仍然是干净的,独立于EntityFramework地狱。我使用Fluent API进行配置,(也可以使用Data anno。原来的ObjectModel仍然是干净的)

在您的上下文中使用ObjectEntity,即DbSet<ObjectEntity>

小心!

你可能会遇到需要一个向下倾斜方法(从父母到孩子)的问题。这就是我在父类(使用AutoMapper)上实现向下转换的方法

using AutoMapper;
...
    public ObjectEntity Downcast() {
        var config = new MapperConfiguration(cfg => cfg.CreateMap<ObjectModel, ObjectEntity>());
        var mapper = config.CreateMapper();
        return mapper.Map<ObjectEntity>(this);
    }

想通知你以及:

直接来自MSDN:

https://msdn.microsoft.com/en-us/library/jj591620(v=vs.113).aspx#Anchor_7

重命名未在模型中定义的外键如果选择

  

如果您选择不在CLR类型上定义外键,但想指定什么   它应该在数据库中具有的名称,执行以下操作:

modelBuilder.Entity<Course>() 
    .HasRequired(c => c.Department) 
    .WithMany(t => t.Courses) 
    .Map(m => m.MapKey("ChangedDepartmentID"));

答案 2 :(得分:1)

在经历了同样的问题并在网络上进行了大量研究后,我也来到了这里,最终放弃了这个想法。但是,在完成项目的另一部分后,我发现这实际上是有可能的(至少现在按预期工作了)。不过在此示例中使用EF Core。

以OP的类为例,该类的键注释已删除

/**
 * Allow SVG MIME Type in Media Upload
 *
 * @param array $mimes Mime types keyed by the file extension regex corresponding to those types.
*/
function cc_mime_types( $mimes ) {
    $mimes['svg'] = 'image/svg+xml';
    return $mimes;
}
add_filter( 'upload_mimes', 'cc_mime_types' );

假设Foo和Bar实体类具有如下导航属性

public class FooBar
{
    public virtual Foo Foo { get; set; }

    public virtual Bar Bar { get; set; }

    //some more 'payload' properties
}

我为FooBar创建了此配置类

public class Foo
{
    ...

    public virtual ICollection<FooBar> FooBars { get; set; }
}

public class Bar
{
    ...

    public virtual ICollection<FooBar> FooBars { get; set; }
}

并在DbContext类OnModelCreating覆盖中应用了配置

public class FooBarConfiguration : IEntityTypeConfiguration<FooBar>
{
    public void Configure(EntityTypeBuilder<FooBar> builder)
    {
        var fkFoo = "FooId";
        var fkBar = "BarId";

        builder.HasKey(fkFoo, fkBar);

        builder
            .HasOne(fb => fb.Foo)
            .WithMany(f => f.FooBars)
            .HasForeignKey(fkFoo);

        builder
            .HasOne(fb => fb.Bar)
            .WithMany(b => b.FooBars)
            .HasForeignKey(fkBar);
    }
}

如前所述,这似乎符合预期。希望它可以帮助其他人搜索相同的问题。