1

I have multiple classes used in another VS project that are interconnected, e.g.:

namespace MyOtherProject
{
    public class A {
        public string Name {get;set;}
    }

    public class B {
        public int Value {get;set;}
        public A Child {get;set;}
    }
}

Now I want to use these classes as POCO for code first in EF. However I don't need all classes in the database but only some of them. So I created a context:

public class MyContext : DbContext
{
    public MyContext () : base("MyContext ")
    {
    }

    public DbSet<B> Bs { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    }
}

When I try to run the project I get this error:

System.Data.Entity.ModelConfiguration.ModelValidationException: One or more validation errors were detected during model generation: MyProject.A: Name: Each type name in a schema must be unique. Type name 'A' is already defined.

Note that the namespace in the error is not the same as the definition of the class A because my class A is defined in another (shared) project. Instead the namespace is the one of the context.

On https://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application I read this:

You could have omitted the DbSet and DbSet statements and it would work the same. The Entity Framework would include them implicitly because the Student entity references the Enrollment entity and the Enrollment entity references the Course entity.

My assumption (not confirmed) is that EF sees that B references A but there is no dataset of type A, so it generates internally a class A and then suddenly finds out there are two such classes.

Anyone know what the exact problem is and what I can do to fix it? I have too many classes that I don't really need, so I don't want to create datasets for each class I have.

Vladimir
  • 1,425
  • 16
  • 31
  • Database.SetInitializer(new CreateDatabaseIfNotExists()); can you add above code inside your context constructor and check – vinodh May 10 '16 at 08:21
  • Sometimes this problem related to your DB_migration – vinodh May 10 '16 at 08:24
  • The database already exists, I cannot create it. – Vladimir May 10 '16 at 08:25
  • If you have database already exist , you can use **DropCreateDatabaseAlways** option if new databse created then we can understand the problem is in migration – vinodh May 10 '16 at 08:49
  • you can use migration up and down method to solve your problem..! – vinodh May 10 '16 at 08:52
  • The problem is not in the database because the exception is thrown before any access to the database is attempted - just when I try to to create a new context instance. – Vladimir May 10 '16 at 08:55
  • oh oh you are using A class reference inside the B Poco Class then how can you create a DBSET B alone without A???? – vinodh May 10 '16 at 09:00
  • I don't need a dataset of type A because I am not using it, it is only used in other projects. I.e. in my project I will never use the property B.Child but it exists and I cannot mark it as NotMapped (because of the other projects I cannot change the classes). – Vladimir May 10 '16 at 09:06
  • What about `modelBuilder.Entity().Ignore(x => x.Child)`? – Slava Utesinov May 10 '16 at 09:45
  • I think that might work but I have about 300 classes with each 100 properties - it will be a bit difficult to remove them all. So I was looking for a possibility to say "ignore all that I have not explicitly stated" or something like that. – Vladimir May 10 '16 at 11:30

1 Answers1

2

First, get all generic type parameters(Type1, Type2...) from DbSet<Type1>. Then you should check for each of this types their internal properties types, i.e. references to another types (as direct link or via ICollection set), - if this internal types not exist at first tablesTypes set we will ignore them.

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {         
        //other stuff.....

        Func<Type, bool> genericFilter = x => typeof(IEnumerable).IsAssignableFrom(x) && x.GenericTypeArguments.Length == 1;

        //All types of your context tables
        var tablesTypes = GetType().GetProperties()
            .Where(x => genericFilter(x.PropertyType))
            .Select(x => x.PropertyType.GenericTypeArguments.First());

        var namespaces2ignore = new List<string> { "Namespace2Ignore1", "Namespace2Ignore2" };
        var toIgnore = new List<Type>();
        foreach (var type in tablesTypes)
            //Ignore internal types, which not exist at tablesTypes
            toIgnore.AddRange(type.GetProperties()
                .Select(x => genericFilter(x.PropertyType) ? x.PropertyType.GenericTypeArguments.First() : x.PropertyType)
                .Where(x => !tablesTypes.Contains(x) && namespaces2ignore.Contains(x.Namespace)
                /*or as you suggested: && typeof(A).Assembly == x.Assembly*/
            ).ToList());            

        modelBuilder.Ignore(toIgnore);
    }

If you want to add condition on specific pairs type-property you can do something like that:

    foreach (var type in tablesTypes)
        foreach(var prop in type.GetProperties()
            .Select(x => new { type = genericFilter(x.PropertyType) ? x.PropertyType.GenericTypeArguments.First() : x.PropertyType, prop = x })
            .Where(x => !tablesTypes.Contains(x.type) && namespaces2ignore.Contains(x.type.Namespace)                
        ).ToList())
            if(!(type == typeof(TestType) && prop.prop.Name == "Test"))
                toIgnore.Add(prop.type);

Now won't be excluded property with name "Test" of type TestType.

Slava Utesinov
  • 13,410
  • 2
  • 19
  • 26
  • Won't this also remove any properties of simple types like string, int? So maybe I have to check also that the type of the property is inside my assembly with incorrect types but that's easy to add. – Vladimir May 10 '16 at 13:30
  • Yes, good comment. At this case you can check - is current type declared at specific Assembly or is it belogs to some list of namespaces(as demonstrated in my corrected answer) – Slava Utesinov May 10 '16 at 13:46
  • Is there a way to ignore properties and not types only? Based on their PropertyInfo – Vladimir May 11 '16 at 07:49
  • Why not? You can add new filter, as shown at my modified answer. – Slava Utesinov May 11 '16 at 12:27
  • Using your suggestion and some hints from http://stackoverflow.com/questions/31066906/ignoring-all-properties-but-some-in-entity-framework-6 I succeeded to fix it. Thanks a lot! – Vladimir May 11 '16 at 13:11