我可以在 Entity Framework Code First 中禁用自动关系吗?

发布于 12-19 03:38 字数 603 浏览 5 评论 0 原文

我注意到实体框架在其最新版本中仍然有很多“自动”功能。一如既往,这确实是一把双刃剑。

具体来说,我使用 OnModelBuilder 事件通过 fluidAPI (http://msdn.microsoft.com/en-us/library/hh295844(v=vs.103).aspx) 在代码中动态创建模型。我有大量实体,但它们并不都符合 Microsoft“标准”。例如,我的 ID 列被命名为 Person_id 而不是 PersonId。因此,实体并不总是自动检测表上的主键,或者至少,它似乎不会这样做。

我不介意在构建模型时明确说明,但令我困扰的是我并不总是确定实体将自动检测哪些属性和关系以及它将错误地忽略或错误识别哪些属性和关系。 由于我的大多数实体也有一个带有辅助方法和属性的分部类(处理枚举等的东西),我非常担心有一天实体会在不应该映射的事物之间自动创建映射(失败可能是实体或一些毫无戒心的程序员)。

有没有办法可以禁用实体的自动关系连接功能,以便我可以在 OnModelBuilder 方法中 100% 明确?或者,至少,我如何知道何时需要添加额外的映射详细信息(例如需要声明字段可选,或者何时不会自动检测特定的导航属性)?

谢谢!

I noticed that Entity Framework still has a lot of "automagical" features in their latest release. As always, this is a truly double-edged sword.

Specifically, I'm using the OnModelBuilder event to create my model on the fly in code using the fluentAPI (http://msdn.microsoft.com/en-us/library/hh295844(v=vs.103).aspx). I have a large set of entities, and they don't all comply with the Microsoft "standards". For example, my ID columns are named Person_id instead of PersonId. As such, Entity doesn't always auto-detect the primary key on a table, or at least, it doesn't seem to do so.

I don't mind being explicit when building the model, but what does trouble me is that I'm not always sure what properties and relationships Entity will auto-detect and which ones it will erroneously ignore or misidentify. Since most of my entities also have a partial class with helper methods and properties (stuff to handle enums, etc), I greatly fear that someday Entity will auto create mappings between things which shouldn't be mapped (the failure could be Entity or some unsuspecting programmer).

Is there a way I can disable Entity's auto-relationship-hookup feature so that I can be 100% explicit in my OnModelBuilder method? Or, at minimum, how can I know when I need to add extra mapping details (like needing to declare a field optional, or when a specific navigation property won't be autodetected)?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

可遇━不可求 2024-12-26 03:38:38

自动魔法首先通过 EF 代码内的约定完成。您可以删除任何约定< /a> 关闭一些魔法,或者你可以 删除它们全部之后,您的 Fluent-API 必须 100% 明确。

The auto-magic is done by conventions inside EF code first. You can remove any of those conventions to turn off some magic or you can remove them all and after that you will have to be 100% explicit in your fluent-API.

倥絔 2024-12-26 03:38:38

好吧,由于删除约定不起作用,有一个简单的方法可以不映射 EF6.x 内的所有未配置属性。

基本方法是使用单独的映射类,在类内进行手动映射后,只需调用一种方法,通过反射将强制忽略所有未配置的属性。

这是我的要点的链接,即实现的位置。还添加了一个示例作为评论: https://gist.github.com/hidegh/36d92380c720804dee043fde8a863ecb

Ok, since the removing of conventions does not work, there's a simple way to not-to map all non-configured properties inside EF6.x

The basic is to use separate mapping classes, and after doing the manual maps inside a class, simply call a method, that with reflection will force to ignore all properties that weren't configured.

Here's a link to my gist, where the implementation is. Also added a sample as a comment: https://gist.github.com/hidegh/36d92380c720804dee043fde8a863ecb

秉烛思 2024-12-26 03:38:38

只需明确实体配置中的关系、键和列,这确实不应该成为问题。

我个人在编码时,让它假设直到它损坏,然后我更正配置。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    Database.SetInitializer<AccountWriteContext>(null);

    modelBuilder.Configurations.Add(new AccountEntityTypeConfiguration());
    modelBuilder.Configurations.Add(new AccountOwnerEntityTypeConfiguration());
    modelBuilder.Configurations.Add(new CreditCardEntityTypeConfiguration());
    modelBuilder.Configurations.Add(new TenantEntityTypeConfiguration());
    //blah blah blah
}


class AccountOwnerEntityTypeConfiguration
     : EntityTypeConfiguration<AccountOwner>
{
    public AccountOwnerEntityTypeConfiguration()
    {
        this.HasKey(p => p.ID);
        this.Property(p => p.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).IsRequired();

        this.HasRequired(o => o.CreditCard).WithMany().HasForeignKey(c => c.CreditCardID).WillCascadeOnDelete(true);

        this.ToTable("AccountOwner", "AccountWrite");
    }
}

Just be explicit on your relationships, keys and columns in your entities configuration and it really shouldn't be an issue.

I personally, while coding, let it assume until it breaks and then I correct the configuration.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    Database.SetInitializer<AccountWriteContext>(null);

    modelBuilder.Configurations.Add(new AccountEntityTypeConfiguration());
    modelBuilder.Configurations.Add(new AccountOwnerEntityTypeConfiguration());
    modelBuilder.Configurations.Add(new CreditCardEntityTypeConfiguration());
    modelBuilder.Configurations.Add(new TenantEntityTypeConfiguration());
    //blah blah blah
}


class AccountOwnerEntityTypeConfiguration
     : EntityTypeConfiguration<AccountOwner>
{
    public AccountOwnerEntityTypeConfiguration()
    {
        this.HasKey(p => p.ID);
        this.Property(p => p.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).IsRequired();

        this.HasRequired(o => o.CreditCard).WithMany().HasForeignKey(c => c.CreditCardID).WillCascadeOnDelete(true);

        this.ToTable("AccountOwner", "AccountWrite");
    }
}
夏花。依旧 2024-12-26 03:38:38

实际上,这段代码删除了所有约定,甚至清除了初始设置...

...但仍然映射了未与 EntityTypeConfiguration 映射的列...

private void RemoveAllConventions(DbModelBuilder modelBuilder)
        {
            new List<string>()
            {
            "_configurationConventions",
            "_conceptualModelConventions",
            "_conceptualToStoreMappingConventions",
            "_storeModelConventions"
            }
            .ForEach(field =>
            {
                var values =
                    (IEnumerable<IConvention>)typeof(ConventionsConfiguration)
                        .GetField(field, BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic)
                        .GetValue(modelBuilder.Conventions);

                modelBuilder.Conventions.Remove(values.ToArray());
            });

            var initialCS = typeof(ConventionsConfiguration)
                        .GetField("_initialConventionSet", BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic)
                        .GetValue(modelBuilder.Conventions);

            new List<string>()
            {
            "ConfigurationConventions",
            "ConceptualModelConventions",
            "ConceptualToStoreMappingConventions",
            "StoreModelConventions"
            }
           .ForEach(field =>
           {
               var values =
                   (IEnumerable<IConvention>) initialCS
                        .GetType()
                       .GetProperty(field, BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.Public)
                       .GetValue(initialCS);

               modelBuilder.Conventions.Remove(values.ToArray());
           });


        }

Actually this code removes all conventions, even clears the initial set...

...but still columns not mapped with EntityTypeConfiguration are mapped...

private void RemoveAllConventions(DbModelBuilder modelBuilder)
        {
            new List<string>()
            {
            "_configurationConventions",
            "_conceptualModelConventions",
            "_conceptualToStoreMappingConventions",
            "_storeModelConventions"
            }
            .ForEach(field =>
            {
                var values =
                    (IEnumerable<IConvention>)typeof(ConventionsConfiguration)
                        .GetField(field, BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic)
                        .GetValue(modelBuilder.Conventions);

                modelBuilder.Conventions.Remove(values.ToArray());
            });

            var initialCS = typeof(ConventionsConfiguration)
                        .GetField("_initialConventionSet", BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic)
                        .GetValue(modelBuilder.Conventions);

            new List<string>()
            {
            "ConfigurationConventions",
            "ConceptualModelConventions",
            "ConceptualToStoreMappingConventions",
            "StoreModelConventions"
            }
           .ForEach(field =>
           {
               var values =
                   (IEnumerable<IConvention>) initialCS
                        .GetType()
                       .GetProperty(field, BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.Public)
                       .GetValue(initialCS);

               modelBuilder.Conventions.Remove(values.ToArray());
           });


        }
长安忆 2024-12-26 03:38:38

我建议使用数据注释属性来执行此操作。例如,[key] 属性可用于定义主键,[table] 属性可用于提供表的名称。 [required] 属性可用于告诉 EF 某个字段是必需的。

在我看来,使用属性语法比使用流畅语法更新模型要容易得多,而且它也是自文档化的,因为属性直接放入目标代码中。

有关详细信息,请参阅此博客文章,其中列出了所有可用属性:

"="">http://blogs.msdn.com/b/efdesign/archive/2010/03/30/data-annotations-in-the-entity-framework-and-code-first.aspx

I would recommend using the Data Annotation Attributes to do this. For example, the [key] attribute can be used to define your primary key, and the [table] attribute can be used to provide the name of your table. The [required] attribute can be used to tell EF that a field is required.

In my opinion, it's much easier to use the attribute syntax than it is to use the fluent syntax to update the model, and it's also self-documenting, since the attributes are placed directly into the object code.

For more info, see this blog post that lists all of the available attributes:

http://blogs.msdn.com/b/efdesign/archive/2010/03/30/data-annotations-in-the-entity-framework-and-code-first.aspx

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文