Can models with EF code fully describe the structure of the database?
No , they do not fully describe the database structure or schema. In addition, there are methods to fully describe the database using EF. They look like this:
You can use the new CTP5s ExecuteSqlCommand method for the database class, which allows you to execute raw SQL commands in the database.
The best place to call the SqlCommand method for this purpose is inside the Seed method, which has been overridden in the custom Initializer class. For instance:
protected override void Seed(EntityMappingContext context) { context.Database.ExecuteSqlCommand("CREATE INDEX IX_NAME ON ..."); }
You can even add unique constraints this way. This is not a workaround, but will be applied since the database will be generated.
OR
If you badly need an attribute, then here it goes
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = true)] public class IndexAttribute : Attribute { public IndexAttribute(string name, bool unique = false) { this.Name = name; this.IsUnique = unique; } public string Name { get; private set; } public bool IsUnique { get; private set; } }
After that, you will have an initializer that you call in your OnModelCreating method, as shown below:
public class IndexInitializer<T> : IDatabaseInitializer<T> where T : DbContext { private const string CreateIndexQueryTemplate = "CREATE {unique} INDEX {indexName} ON {tableName} ({columnName});"; public void InitializeDatabase(T context) { const BindingFlags PublicInstance = BindingFlags.Public | BindingFlags.Instance; Dictionary<IndexAttribute, List<string>> indexes = new Dictionary<IndexAttribute, List<string>>(); string query = string.Empty; foreach (var dataSetProperty in typeof(T).GetProperties(PublicInstance).Where(p => p.PropertyType.Name == typeof(DbSet<>).Name)) { var entityType = dataSetProperty.PropertyType.GetGenericArguments().Single(); TableAttribute[] tableAttributes = (TableAttribute[])entityType.GetCustomAttributes(typeof(TableAttribute), false); indexes.Clear(); string tableName = tableAttributes.Length != 0 ? tableAttributes[0].Name : dataSetProperty.Name; foreach (PropertyInfo property in entityType.GetProperties(PublicInstance)) { IndexAttribute[] indexAttributes = (IndexAttribute[])property.GetCustomAttributes(typeof(IndexAttribute), false); NotMappedAttribute[] notMappedAttributes = (NotMappedAttribute[])property.GetCustomAttributes(typeof(NotMappedAttribute), false); if (indexAttributes.Length > 0 && notMappedAttributes.Length == 0) { ColumnAttribute[] columnAttributes = (ColumnAttribute[])property.GetCustomAttributes(typeof(ColumnAttribute), false); foreach (IndexAttribute indexAttribute in indexAttributes) { if (!indexes.ContainsKey(indexAttribute)) { indexes.Add(indexAttribute, new List<string>()); } if (property.PropertyType.IsValueType || property.PropertyType == typeof(string)) { string columnName = columnAttributes.Length != 0 ? columnAttributes[0].Name : property.Name; indexes[indexAttribute].Add(columnName); } else { indexes[indexAttribute].Add(property.PropertyType.Name + "_" + GetKeyName(property.PropertyType)); } } } } foreach (IndexAttribute indexAttribute in indexes.Keys) { query += CreateIndexQueryTemplate.Replace("{indexName}", indexAttribute.Name) .Replace("{tableName}", tableName) .Replace("{columnName}", string.Join(", ", indexes[indexAttribute].ToArray())) .Replace("{unique}", indexAttribute.IsUnique ? "UNIQUE" : string.Empty); } } if (context.Database.CreateIfNotExists()) { context.Database.ExecuteSqlCommand(query); } } private string GetKeyName(Type type) { PropertyInfo[] propertyInfos = type.GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public); foreach (PropertyInfo propertyInfo in propertyInfos) { if (propertyInfo.GetCustomAttribute(typeof(KeyAttribute), true) != null) return propertyInfo.Name; } throw new Exception("No property was found with the attribute Key"); } }
Then reload OnModelCreating in your DbContext
protected override void OnModelCreating(DbModelBuilder modelBuilder) { Database.SetInitializer(new IndexInitializer<MyContext>()); base.OnModelCreating(modelBuilder); }
To apply an index attribute to an Entity type, with this solution you can have several fields in the same index, simply using the same name and unique.
OR
You can migrate later.
Note: I took this code from here .