2

I have convention to put [Key] as an Annotation Attribute in Entity and rest of the configuration into FluentAPI (ForeignKeys mostly). I worked great, but then I found out that EF6 has this "magic conventions", that will create PK or FK if the name is in the specific format (I found out asking this question).

Then I thought, what if I'm doing something wrong and EF is saving my butt? And I don't even know that. So I removed all conventions, following this answer. Here's the code:

private void RemoveAllConventions(DbModelBuilder modelBuilder)
{
    var conventions = AppDomain.CurrentDomain.GetAssemblies()
        .SelectMany(a => a.GetTypes().Where(t => t.IsClass && t.GetInterface("IConvention") != null));

    var remove = typeof(ConventionsConfiguration).GetMethods().Where(m => m.Name == "Remove" && m.ContainsGenericParameters).First();
    foreach (var item in conventions)
    {
        try
        {
            remove.MakeGenericMethod(item).Invoke(modelBuilder.Conventions, null);
        }
        catch (Exception)
        {
        }
    }
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    RemoveAllConventions(modelBuilder);
}

After that I got exceptions like:

CodeFirstNamespace.Item: : EntityType 'Item' has no key defined. Define the key for this EntityType.

The thing is.. Item does have [Key] attribute! When I add:

modelBuilder.Entity<Item>().HasKey(i => i.itemID);

The exception is gone.

Looks like, if you start Fluent API, you must put everything there. Is that true? Or I'm doing something wrong?

Ish Thomas
  • 2,270
  • 2
  • 27
  • 57
  • Data annotations are also applied with conventions, thus you shouldn't be surprised that the `[Key]` attribute has no effect after you have removed all conventions. For instance, the convention (class) responsible for `Key` attribute is called ... well, `KeyAttributeConvention`. – Ivan Stoev Mar 10 '18 at 18:56

1 Answers1

3

The issue is that you are removing all conventions on load, then using Fluent API. You can freely mix use of annotations and Fluent API. They each have strengths and weaknesses. I use both, wherever each is appropriate, in a project currently.
However, if you remove all your conventions every time OnModelCreating is called, you're removing all previous conventions. This includes annotations, which are loaded before the system calls OnModelCreating

Zarenor
  • 1,161
  • 1
  • 11
  • 23
  • So, where should I call `RemoveAllConventions` method? – Ish Thomas Mar 09 '18 at 14:52
  • You shouldn't. Entity framework does all of it's inference very intentionally, and will trust you to annotate what you need to annotate, and spell out in Fluent API whatever else you need to explicitly define. The conventions it infers will never override the conventions you explicitly define. – Zarenor Mar 09 '18 at 14:55
  • I just thought it would be great way to test whether I didn't forget anything in the fluent api – Ish Thomas Mar 09 '18 at 14:58
  • I want to remove ONLY relationship conventions. Not primary key – Ish Thomas Mar 09 '18 at 14:59
  • The reason you're getting an inferred relationship convention is because you have an `ItemID` property, and the `Item` class has a list of `ItemNote`s. You are free to define this relationship in Fluent API however you like, but EF will always infer this convention. You shouldn't be concerned that it's doing so - that is very intentional. – Zarenor Mar 09 '18 at 15:03
  • If you are willing to simply drop somebody else's code removing the conventions in without working through how it works yourself, then you shouldn't be surprised when it has unintended side effects. You could work through `RemoveAllConventions`'s code, and see about removing only relationships, but if you do not understand how the code is reflecting against your code to remove all of them, then you will also not understand how to remove only some. Additionally, you probably should not change this behavior of EntityFramework - it's intended to both save you trouble and time. – Zarenor Mar 09 '18 at 15:07