MVC4 code first force database column name - c#

I have the following problem: I have a hierarchy of entities that uses inheritance. I have a two identical fields( the name and type is the same ) in two of the sub-entities. When I try to "Update-Database -Force" on the project EF5 complains that there are there is already a column with name X.
The way EF5 generates the tables is that it actually generates single table and puts there all the fields of the base entity plus the all the fields of the derived entities.
Is there a way to force a different database column name from the property name.
Are there any other solutions( I know it might be architectural problem to duplicate data but making this common will introduce more complex database hierarchy that I don't want to use ).
Thanks:)

This can be done in one of two ways, either using Fluent API or property attributes on your class properties.
[Column("ColumnName")]
public string PropertyName
{
get;
set;
}
See MSDN - ColumnAttribute Class for more details on the column attribute.
Otherwise, use Fluent API. Within your context class-
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<YourClass>().Property(yc => yc.PropertyName).HasColumnName("ColumnName");
See MSDN - HasColumnName extension method for more on this method.
The article linked by Baximilian will be useful in learning more about this.

If I understand you correctly, you need to change column name in DB for field, so you can use ColumnAttribute.
You can find more information here

Related

Mapping table name in Entity, when you define Code-First by existing Database

I already have defined my Database, and now I'm doing Code-First, creating the Objects so they fit with the current database.
My only problem is that the mapping table names dont entirely aggree with me.
My primary table is "Movies". Then I have a many-to-many to "Actors", and another many-to-many to "Genres".
My problem is >
The mapping table name for Actors is totally fine.. Entity aggrees with "MovieActors", BUT! The Genre table, Entity wants to call "GenreMovies".
Why does entity want this? And how can I force it to use "MovieGenres"?
Please let in mind that I have already created the Database, and dont want entity to create any tables.
If your class is named Genre, by convention Code First presumes this will map to a table named Genres. If that's not the case, you can specify the name of the table with the Table attribute. Here for example, the annotation is specifying that the table name is GenreMovies.
[Table("GenreMovies")]
public class Genre
Another option is use Fluent Api. The easiest way is overriding the OnModelCreating method in your Context:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Genre>().ToTable("GenreMovies");
}
If you want to change the name of that Table in DB, I suggest you learn how to use Code First Migration

EntityFramework 5 Validation

I'm looking for some advice. I'm working with EF 5 and I have a generic repository which handles all of the CRUD transactions with the database. This works fine, But i want to add a "Last Gap" safeguard to ensure that the entity is valid before the Data Access Layer attempts changes in the database.
Right before I do something like this :-
DataLayer.Create<TEntity>(entity);
I want to Validate the entity and throw an exception if the validation fails.
What would you guys use as the preferred method?
Using Data Annotations
You can use data annotations directly in your entity. With data annotations, EF will validate the property for you and if it is not valid, an exception will be thrown.
For example, if you want Name to be required, you can do something like:
public class Person
{
[Required]
public string Name { get; set; }
// other members
}
Aside from validation, EF will also set the corresponding column to be not null instead of the default null for strings.
Using the Fluent API
If you don't want to litter your entities with data annotations, you can use the fluent API instead. Following is the equivalent of the above code:
public class MyContext : DbContext
{
public DbSet<Person> People { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Entity<Person>().Property(p => p.Name).IsRequired();
}
// other members
}
My answer applies to EF Code First and may not apply for other workflows.
Sometimes you have to go to the database to check whether inserting or updating an entity keeps the repository in a valid state - such as when you need to ensure the natural key is unique. That isn't currently handled by a data annotation or the Fluent API, although it has been discussed. See unique constraints in entity framework And this work item.
In the meantime, when you have to go to the database then DbContext will be involved somewhere, and DbContext has an Overridable method called ValidateEntity. See this article: Entity Framework Validation.
I put the code I use in another answer here
And more about how I've structured the validation in MVC here.
I wouldn't do validation at the DAL, but if you do, you might be interested in Validation with the Data Annotation Validators

Entity Framework table-per-type inheritance - adding inherited type to database giving error "Invalid column name"

I've been at this for a while, and I really cannot figure it out. I'm using EF5, Mvc 4, table-per-type inheritance.
I have classes Tenant and Landlord that inherit from UserProfile. When registering a user selects what account type they want, and based on this selection the details they enter on the form (username, first name, last name, email, account type, password) should be added to UserProfile table. I then want the PK of that table to be added as a foreign key to table that matches the account type they selected, either Tenant or Landlord.
I was trying to achieve the above using this method, but that resulted in the problems described in that question.
I've now created a RegisterTenantModel class, with properties that map to a Tenant, and I'm passing an object of type RegisterTenantModel to the AccountController/Register like so...
// ...
if (tenantModel.AccountType == AccountType.Tenant)
{
using (var db = new LetLordContext())
{
var t = db.UserProfile.Create<Tenant>();
WebSecurity.CreateUserAndAccount(tenantModel.UserName, tenantModel.Password,
t = new Tenant
{
AccountType = tenantModel.AccountType,
DateWantToRentFrom = DateTime.Now,
DateWantToRentTo = DateTime.Now,
DesiredPropertyLocation = "",
Email = tenantModel.Email,
FirstName = tenantModel.FirstName,
UserId = WebSecurity.CurrentUserId,
UserName = WebSecurity.CurrentUserName
// More properties that map to Tenant entity
// ...
},
false);
db.SaveChanges();
...but now I'm getting an error Invalid column name for each of the column names inside t= new Tenant.
Has anyone ever had to do something similar? Am I approaching this the right way? Help would be much appreciated.
EDIT
Based on what Antonio Simunovic posted below, I think I've come to realise what the problem is. My WebSecurity.InitializeDatabaseConnection() goes like this...
WebSecurity.InitializeDatabaseConnection("LetLordContext", "UserProfile",
"UserId", "UserName", autoCreateTables: true);
...so when I call Websecurity.CreatUserAndAccount() in AccountController/Register it's writing to the UserProfile table as per the parameters in WebSecurity.InitializeDatabaseConnection(). Looking at the question linked above, you'll see that, based on the account type selected on the form, either a Tenant or Landlord will be added to the UserProfile table by calling...
var tenant = db.UserProfile.Create<Tenant>();
//...
db.UserProfile.Add(tenant);
db.SaveChanges();
...resulting in duplicate entries being added to the UserProfile table.
I think the solution is to create a new table, and point WebSecurity.InitializeDatabaseConnection() at it.
What does your WebSecurity.InitializeDatabaseConnection() method call looks like? That call identifies database table to store user data.
WebSecurity.CreateUserAndAccount() method does not use context to store supplied data, it simply maps object property names of third call argument to columns in table defined in InitializeDatabaseFile() method.
If you're not familiar with SimpleMembership mechanics, take a look at this article:
http://weblogs.asp.net/jgalloway/archive/2012/08/29/simplemembership-membership-providers-universal-providers-and-the-new-asp-net-4-5-web-forms-and-asp-net-mvc-4-templates.aspx
I saw exactly the same symptoms, and it was because I hadn't declared the base class as a DbSet<BaseClassName> on the DbContext.
(Counterintuitive, and I never need to refer to the collection of base class entities in my application, but there you go.)
I have seen this error when I forget to annotate the subclass with the table name in TPT.
[Table("Tenant")]
public class Tenant : UserProfile { ...
Could it be as simple as this?
EDIT
A quick search also recommends pairing down your fields in the Entity and adding them back in one at a time to see if a single field is to blame (and it will provide an error message that indicates many failed columns). This sounds a little suspect to me, but might be worth a try:
Entity Framework 5 Invalid Column Name error
Solution
Ensure that all derived classes are explicitly mapped to tables. Two simply ways to do this are:
TableAttribute class attribute: [Table("Tenant")]
ToTable Fluent API method: ToTable("Tenant")
Ensure that the base type is abstract.
Ensure that you are not calling the MapInheritedProperties configuration method for any tables. That method implies TPC.
Ensure that the base type is registered as part of the model. Two simple ways to do this are:
Add an accessor property to your subclass of DbContext:
public DbSet<UserProfile> Users { get; set; }
Override OnModelCreating in your subclass of DbContext and call DbModelBuilder.Entity:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<UserProfile>();
}
Explanation
As the error message indicates, Entity Framework appears to be looking for the "base" table's columns in the "derived" table. This indicates that it's trying to use "Table per Concrete Type" (TPC) inheritance rather than "Table per Type" (TPT).
Making Entity Framework use TPT is quite fiddly. If you very carefully study the example implementation at Inheritance with EF Code First: Part 2 – Table per Type (TPT), you might spot what you're missing. The follow-up article, Inheritance with EF Code First: Part 3 – Table per Concrete Type (TPC), summarises the required configuration as follows:
As you have seen so far, we used its Requires method to customize TPH. We also used its ToTable method to create a TPT and now we are using its MapInheritedProperties along with ToTable method to create our TPC mapping.
My experimentation has shown that the above summary is oversimplified. It appears that a single minor seemingly-unrelated configuration difference can cause an unexpected inheritance strategy to be used.

Entitiy Framework, use same model for two tables with same layout but different table names

I have two tables that have the same layout -
Report Table
ID
ReportCol1
ReportCol2
In another database I have
Reporting Table
ID
ReportCol1
ReportCol2
I want to use a single entity model called Report to load the data from both of these tables.
In my context class I have
public DbSet<Report> Report{ get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ReportMap());
}
In my call to the first database Report table I get the results as expected.
I change the connection string to point to the second database, but I can't change the name of the table in the table mapping.
I don't want to use stored procs for the reason outlined in my comment.
What can I do, short of the tables names in the database(that is not an option).
Have you tried this fluent API modelBuilder.Entity<Report>().ToTable("Reporting"); ? You may need to write this so it conditionally does this based on which database you are connecting to. You may need to have your configuration allow you to say "DatabaseA uses this mapping and connection string", and "DatabaseB uses this other mapping and conenctions string", and rather than changing the connection string, you specify which database by some name/key, and your app looks up that name to determine which mapping code to run.
if(dbMappingconfig == DbMapping.A)//some enum you create
{
modelBuilder.Entity<Report>().ToTable("Reporting");
}
If your goal is to be able to pass these entities to other methods like DisplayReport(Report r) so that you don't have to duplicate code, you could have both Reporting and Report classes implement a IReport interface.
EF also supports inheritance hierarchies, so you could have them inherit from the same class, BUT I havfe a strong feeling that will not work across databases.
If the OnModelCreating doesn't rerun, it's probably already cached. Put modelBuilder.CacheForContextType = false; in there so it doesn't cache it in future, and to clear the current cache I think you can just do a Clean+Rebuild. This will come at the price of rebuilding the model everytime instead of reusing a cache. What you'd really want is use the cache up until the connection string changes. I don't know of anyway to manually clear the cache, but there might be a way. You can manage the model building yourself:
DbModelBuilder builder = new DbModelBuilder();
// Setup configurations
DbModel model = builder.Build(connection);
DbCompiledModel compiledModel = model.Compile();
DbContext context = new DbContext(connection, compiledModel);
But that will introduce additional complexities since you will need to manage the caching yourself.
While searching on this, I came across this that looks like they are trying to accomplish the same thing, as well as having gone down the same page, see Final section in question: How to map an Entity framework model to a table name dynamically
Are you able to create the same named view in each database and map to that instead of a variable table name?
I have 2 copies of tables with different names in my solution and deal with that by having 2 contexts and 2 sets of map files (generated text templates)

Changing the Nhibernate entity to point to new table

I am using FLH and recently I changed the name of the table. I dont want to propagate the changes all the way across my layers. Is there a way, where I can retain the same entity name and just change the mapping. For example, my current entity name is Issuer and the table name is also issuer. However, the table name is changed to "counterparty" and I want to retain the entity name as Issuer. How can I achieve this?
I found the answer for the above problem. I made use of IAutomappingOverride interface.
The sample code is below
public class IssuerMap : IAutoMappingOverride<Issuer>
{
public void Override(AutoMapping<Issuer> mapping)
{
mapping.Table("Counterparty");
}
}
Also found some related links
Fluent Nhibernate - How to specify table name
You would need to have a Table("Counterparty") clause in your classmap, as in How to specify table name in Fluent NHibernate ClassMap class?

Categories