Background: I’m beginning a project to convert a web application using Linq2Sql to use Entity Framework (v6) instead. I have a lot of experience with L2S, but I’m brand-new to EF. Since our application and its database already exist, we’re using the “Database First” approach. Also, the database is evolving, so we’re making changes in the schema and the model is updated from the revised database, which regenerates code for the EF model each time.
For many of our entities (database tables), we set default values in our code whenever an entity is constructed. In Linq2Sql it’s easy: define a partial class for the entity, and add a method to the class like this:
partial void OnCreated() { SomeProperty = SomeDefaultValue; }
Whenever Linq2Sql constructs a new entity object, it calls the OnCreated() method you define, and the default values are set as desired. It works great.
The Problem: In EF, I don’t see a way to do this in a Database First scenario.
If I modify the model code generated by EF, the model code is overwritten whenever we update the model after a database revision.
If I define a partial class for the entity in a separate file and define a constructor, the compiler complains that the constructor is already defined.
There doesn’t seem to be any support for something like L2S's OnCreated() method, either.
Any suggestions?
EDIT: Thanks everyone for the helpful comments, but I think I need to point out an important consideration: My goal is to use the database-first approach and stick with it, rather than switching to code-first. When the database schema changes over time I want the EF Designer (or POCO Generator or whatever tools) to update my EF entity classes to match. All without losing my additions to initialize class properties when the class is constructed in the application. This is easy in Linq2Sql, but I just don’t see a way to accomplish this in EF database-first. All suggestions are welcome!
1 . Open .edmx file
2 . Select the field that has the default value and go to the properties
3 . then select StoreGeneratedPattern
4 . then change the value to Computed
i think it's worked.
OP here – I’ve given credit for the answer to ErikEJ but I’d like to recap what I’ve learned on this topic to share with others. There are three goals:
Use the database-first approach and stick with it, even as the database schema is changed over time. That is, have EF produce the code for each database table entity, based on a preexisting database, and update the code when the database is altered.
Provide a mechanism to initialize entity object properties each time the object is constructed, such as Employee.Dependents = 1, for example. (I know simple defaults can be set by the database schema, but more complex initializations must be executed by code.)
The custom initialization code must be preserved when the database schema is altered and EF regenerates the model code.
EF doesn’t provide a way to set properties each time an entity object is constructed in the database-first scenario. Editing the EF-generated code doesn’t work because it gets overwritten whenever EF regenerates the code after a change to the database schema. So far, four workarounds come to mind:
One idea is to add a constructor with more than the default zero-parameter constructor for each entity class. For example, c = new Customer(x) rather than the default c = new Customer(). Application code would call the new constructor, which would inherit the default constructor and add additional code to initialize the class properties. This avoids duplicating the default constructor, something that isn’t permitted by C#. The new constructor is in a separate partial class file, so it will not be overwritten when EF generates updated models from the database.
However, there is a risk that the application programmer may call the default constructor by accident, leading to subtle bugs.
Another solution is to wrap the entity classes in another class, say, a Customer2 class wrapped around the Customer class. The new class would inherit the original class and add initialization code for any properties as needed.
Since these new classes are separate from the original entity class code, they will not be overwritten by EF when it regenerates model code. It may be possible to hide the entity classes from the top-level application code, to avoid accidentally referring to the original classes by accident. If so, this should be a good technique, although I haven’t tested it yet.
A third-party tool, EntityFramework Reverse POCO Generator, is a help. It generates POCO model code much as EF does, but it is not EF. It has an option to generate partial classes, and the entity classes include a InitializePartial() method much like Linq2Sql’s OnCreated(). I think this will work fine for regenerating code as the database is altered over time. My concern here is that this is a third-party product, and there’s always a risk that it can become obsolete or unsupported.
Finally, you can alter the template that EF uses to generate code. The basic idea is to have the generated code add “partial void OnCreated()” to each class, and this lets us use the same convenient technique built into Linq2Sql. I assume newer versions of EF may overwrite the template changes, but it’s just one change in the template rather than changes to every entity class. This method is described here (How to efficiently set default entity values in Entity Framework 6, Database First) and the YouTube video is here (https://www.youtube.com/watch?v=i8J2ipImMuU).
Thanks to all who contributed! I hope this page is helpful to others, so you don’t have to burn as much time as I did looking for a solution.
Use the EF Reverse poco template- it will derive defaults from the database. You can override the InitializePartial method in your partial class to set defaults in code.
Coming from the EF background, I generally do it in the code first migration manually. In the up function of the generated migration, you can do something like this
AddColumn("dbo.Person", "IsActive", c => c.Boolean(nullable: false, defaultValue: true));
AddColumn("dbo.Person", "Name", c => c.String(nullable: false, defaultValue: "Mirza"));
Or to add default SQL value, use
AddColumn("dbo.Person", "CreatedDate",
c => c.String(nullable: false, defaultValueSql: "GETDATE()"));
However there's a downside of this approach in my opinion which is you have to keep a track of your (useless) migrations.
Just found this post looking for an answer to the same issue. Here's a work around that works for me.
Create a partial class for the entity (DB Table) you want to specify default values for, eg:
namespace myApplication.MyModel
{
public partial class myEntityName
{
public myEntityName(bool InitialiseOnConstruct) : this()
{
if (InitialiseOnConstruct)
{
this.property1 = defaultValue1;
this.property2 = defaultValue1;
}
}
}
}
Then in the code, to construct the entity:
thisEntity = new EntityName(true);
OK, it's an extra step, but it works. Hope that helps.
Related
I want to persist a linked list of objects using in my ASP.Net Core application. For simplicity, I'll use blog and comments; although the real context is much more complex.
I scaffolded two tables, and changed ICollection<Comment> to LinkedList<Comment>. However, if I create an initial migration and apply to an empty database, I don't get anything "linked" in the database (no next or previous). Also, if I seed the data, and then do something like this:
var comments = _context.blogs.First().Comments
I get null. If I leave public virtual ICollection<Comment> Comments, I get the IEnumerable just fine.
I tried to use LinkedList<LinkedListNode<Comment>> instead, and it works nice unless I try to create a migration. Getting an error
No suitable constructor found for entity type 'LinkedListNode'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'value' in 'LinkedListNode(Comment value)'; cannot bind 'list', 'value' in 'LinkedListNode(LinkedList list, Comment value)'.
I couldn't find any guidance how to implement LinkedList in C#/.NET Core (obviously, I can do it manually, having next and prev fields - but I would very much prefer to use framework capabilities, if possible!)
I don't know much about MS SQL server, but the whole next and prev parts in mysql won't work because you can't map the keys it would require to track the fields properly because each link has to have an id in a database to link to. only thing I know of would be create the next/prev yourself and use some custom data persistence or data annotations. but the foreign key constraints I'm pretty sure on any relational database will prevent you from auto persisting those types of fields. reason being tracking deletes, inserts etc would be a nightmare because if you remove the middle of the chain, then the database has to try and guess where to link the ends to
Here's my situation:
I have been working on an ASP.NET MVC 3 application for a while. It has a database (built out of a db project; I'm going db-first) for which I have an edmx model and then a set of POCOs. My entities have plural names in the database and POCOs have singular names. Everything maps nicely without a problem.
Or used to until I added a new table (called TransactionStatuses). Now all of the old entities still work but the new one does not. When I try to eagerly load it together with a related entity:
var transactions = (from t in db.Transactions.Include(s => s.TransactionStatus) //TransactionStatus - navigation property in Transactions to TransactionStatuses
where t.CustomerID == CustomerID
select t).ToList();
I get
Invalid object name 'dbo.TransactionStatus'.
I even did a simpler test:
List<TransactionStatus> statuses = db.TransactionStatuses.ToList();
= same result.
I have updated (and even re-created) edmx from the db and have gone through it back and forth trying to figure out what is different about the mapping for dbo.TransactionStatus*es* which trips the whole thing up.
If somebody can point me in the direction of a fix it'd be wonderful.
P.S. Turning off pluralisation is not an option, thanks.
Update: I figured it out - my answer below.
This is probably happening because even though the intention was to use the Database First flow, in actual fact the application is using Code First to do the mapping. Let me explain a bit more because this can be confusing. :-)
When using Database First with the EF Designer and the DbContext templates in Visual Studio three very important things happen. First, the new Entity Data Model wizard adds a connection string to your app containing details of the Database First model (i.e. the EDMX) so that when the application is run it can find this model. The connection string will look something like this:
<connectionStrings>
<add name="MyEntities"
connectionString="metadata=res://*/MyModel.csdl|res://*/MyModel.ssdl|res://*/MyModel.msl;provider=System.Data.SqlClient;provider connection string="data source=.\sqlexpress;initial catalog=MyEntities;integrated security=True;multipleactiveresultsets=True;App=EntityFramework""
providerName="System.Data.EntityClient" />
</connectionStrings>
Second, the generated context class makes a call to the base DbContext constructor specifying the name of this connection string:
public MyEntities()
: base("name=MyEntities")
{
}
This tells DbContext to find and use the "MyEntities" connection string in the config. Using "name=" means that DbContext will throw if it doesn't find the connection string--it won't just go ahead and create a connection by convention.
If you want to use Database First, then you must use a connection string like the one that is generated. Specifically, it must contain the model data (the csdl, msl, ssdl from the EDMX) and you must make sure that DbContext finds it. Be very careful when changing the call to the base constructor.
The third thing that happens is that OnModelCreating is overridden in the generated context and made to throw:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
This is done because OnModelCreating is only ever called when using Code First. This is because OnModelCreating is all about creating the model, but when you are using Database First the model already exists--there is nothing to create at runtime. So if OnModelCreating is called then it is probably because you started using Code First without meaning to, usually because of a change to the connection string or the call to the base constructor.
Now, it might be that you want to use Code First to map to an existing database. This is a great pattern and fully supported (see http://blogs.msdn.com/b/adonet/archive/2011/03/07/when-is-code-first-not-code-first.aspx) but you will need to make sure mappings are setup appropriately for this to work. If the mappings are not setup correctly then you will get exceptions like the one in this question.
Got it!
Horrible, horrible experience...
In short: EF cannot correctly pluralize entity names that end with "s" (e.g. "status", "campus", etc.)
Here's how I got it and proof.
I've created and re-created my original set up several times with the same result.
I also tried renaming my table to things like TransStatus and the like - no luck.
While I was researching about this I came across the pluralization article by Scott Hanselman where he added pluralization rules for words like sheep and goose. This got me thinking "what if he problem is in the actual name of the entity?"
I did some searching about the word status in particular and found this report of the problem on Connect. I rushed to try renaming my entity...
Renaming TransactionStatuses to TransactionStates (while even keeping the columns as StatusID) fixed the issue! I can now get List<TransactionState> statuses = db.TransactionStates.ToList();
I thought the problem was with the particular word status in the name... But after vocally complaining about this to a friend I was suggested that maybe the problem is with the word ending with "s"... So I decided to check it out.
I set up another table called Campuses and matching POCO Campus (and updated the edmx). Did the simple test List<Campus> test = db.Campuses.ToList(); and got the now expected
Invalid object name 'dbo.Campus'.
So there you go, the mighty EF cannot handle pluralization of words ending with "s". Hopefully, the next poor bugger hitting the problem will find this question and save him- or herself 3-4 hours of pain and frustration.
You mention EDMX but I can't tell if you are doing databse first with EDMX or code first and just using EDMX to see what's going on.
If you are using Code First, then you can use a configuration to specify the table name. Data Annotation is [Table("TransactionStatuses")], fluent is modelBuilder.Entity().ToTable("TransactionStatuses").
(I'm typing the annotation and fluent code from memory so double check references. ;) )
If you are using database first, the SSDL should absolutely be aware of the name of the database table, so I'm guessing that you are using code first & the edmx is just for exploration. (???)
hth
Sigh. Same type of an issue with the class and model Photo and Video; it is looking for the table Photoes and Videoes. I hate to just change the table name, but not much of a choice it looks like.
I have these two related tables Client (ClientId, Name) and ClientDescription (ClientDescriptionId, (FK) ClientId, Description). That is to say each Client can have many associated descriptions. Now, when displaying the a list of ClientDescriptions, I also need to know what the Name of it's associated Client is.
Now you'll probably say that I allready have this information, since I can simply follow my navigation property back to the associated Client and use its Name. I can't do that because I'm autogenerating a grid in Ria services, and this just gives me a count for navigation properties, and I haven't found a way to flatten this down in my metadata file. Hence why I want a property.
The whole idea is that I want to be able to add a new field to my database, update my entity classes from the database and regenerate my domain service, and the new field should just pop up in my grid. I shouldn't have to update my xaml just because my database happen to have an extra field.
So, what I would like to do is add a ClientName field to the entity (clr object), but keep my database clean (no such denormalization in the db).
So, I generated my edmx, and added a new property named ClientName. Set it to StoreGeneratedPattern.Computed, and compiled. I then get a nasty little error
Error 3004: Problem in mapping fragments starting at line NN: No mapping specified for properties (etc..)
The solution apparently is to generate my database from my edmx. (Or that's what answers to questions about that error seems to yield.) But this generates an actual DB-field, which I don't want, so that answer doesn't apply to my case.
So my question is: How can I denormalize my clr entity, but keep my db tables normalized?
Edit: I guess this question can be generalized a bit. The issue would be the same if ClientDescription contained a few numeric fields that I wanted to do some calculations on, and I wanted the result available as a field and the algorithm should be in c# rather than in my database.
To answer your more generalized question:
Entities are generated by the Entity Framework with a partial keyword.
This means that the code of an entity can be split in multiple source files in the same namespace and assembly. One will contain the generated code from the Entity Framework, the other will contain custom properties and methods.
If for example, your entity has the database fields Price and Amount you could add a property in the partial class TotalPrice which would return Price * Amount.
Then the algorithm will be C# and your database won't know about the extra property.
I'm trying to write an add-on to Entity Framework Code First and I need a way to get the configuration of the model columns at run time. For example, this is the code setup on OnModelCreating by the DbModelBuilder:
builder.Entity<NwdEmployee>()
.Property(n => n.ReportsToID).HasColumnName("ReportsTo");
Once this is done, EntityFramework knows that my property's name is different to the column name in the table, but how can I find that the string "ReportsTo" relates to ReportsToID myself at runtime? Ideally, I'm trying to write a method such as a following:
public string GetMappedColumnName<TFrom>(DbContext context,
Func<TFrom, object> selector);
Which would be used like:
string mappedColumnName = GetMappedColumnName<NwdEmployee>(context,
x => x.ReportsToID);
I just don't know where to find the mapped column names within the DbContext. Are they even accessible?
Theoretically yes. Practically I'm not sure because with simple test I wasn't able to get those information at runtime - I see them in debugger but I cannot get them because the type I need to use is internal in entity framework.
The theory. All mapping information are available at runtime but not through reflection. They are stored in the instance on MetadataWorkspace class which was definitely not designed for direct usage because every interaction with this class demands some time spend in debugger before you find how to get data you need. This data are not accessible through DbContext API. You must convert DbContext back to ObjectContext and access the MetadataWorkspace.
ObjectContext objContext = ((IObjectContextAdapter)dbContext).ObjectContext;
GlobalItem storageMapping = objContext.MetadataWorkspace.GetItem<GlobalItem>("NameOfYourContextClass", DataSpace.CSSpace);
Now storageMapping is instance of System.Data.Mapping.StorageEntityContainerMapping class which is internal. As I understand it this class should be runtime representation of MSL = mapping between storage and conceptual model.
If you use debugger you can explore the instance and you will find information about mapping between properties and columns (its quite deep nested) so you can also use reflection to get them but it is reflection on non public interface of classes you don't own so any .NET framework patch / fix / update can break your application.
Following on from an SO dicsussion here, I have implemented partial classes so as to create default datetime values for my Created and Modified database fields in a Constructor.
Now the problem is that my database has 100+ tables, and 75+ of them have the same basic structure which includes a Created and a Modified column definition.
So.. Instead of creating 75+ partial classes which I need to maintain, is there any way I can create a base class which every EF type inherits from, which inherits the default constructor to populate the DateTime values for Created and Modified?
EDIT: Worthy of note is that I am using EF 4.0
You can certainly specify your own base class with both EF4 and EF1, though it's a lot easier with EF4. Right click on the design surface and you should see an option to add a Code Generation Item. Select the ADO.Net entity object generator. This will a T4 file to your project (.tt extension) that specifies the template to use to generate your entity classes from the model. To specify a different base class, look inside it for a line like
Private Function BaseTypeName(ByVal entity As EntityType, ByVal code As CodeGenerationTools) As String
Return If(entity.BaseType Is Nothing, "EntityObject", MultiSchemaEscape(DirectCast(entity.BaseType, StructuralType), code))
End Function
Replace EntityObject with your base class. Note that if you are using this template then your base class must inherit from System.Data.Objects.DataClasses.EntityObject - you could use a POCO template instead, but this will probably be enough for you.
You can certainly tell EF to use a base class for your entities (it's right in the designer as a property for the entity)...but if you want to make sure of the default value for this field, perhaps you could hook into the two events on your ObjectContext SavingChanges and ObjectMaterialized.
http://msdn.microsoft.com/en-us/library/system.data.objects.objectcontext.savingchanges.aspx
http://msdn.microsoft.com/en-us/library/system.data.objects.objectcontext.objectmaterialized.aspx
You could use these opportunities to inject the default value(s) that you want to use. So in your SavingChanges handler, for example, you could check the ObjectStateManager on the context to see if the state of the relevant entity is EntityState.Added, then set the Created and Modified dates as desired.
Alternatively, as suggested, is there a reason the default value for the column in SQL Server can't just be GetDate()? (Assuming you're using SQL Server)....