I am trying to write a model for use within EF6 which includes a property that I would like to calculate in C# (not SQL). My model looks like this:
public class UploadRequestWorkingHours : UploadRequest
{
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public int WorkingHoursSinceResponseDate
{
get { return DateUtils.WorkingHoursSince(ResponseDate); }
private set { }
}
}
The UploadRequest class contains the details, and this derived class introduces a property that should be calculated by LINQ/EF/whomever when the model is serialized.
Unfortunately, this property — WorkingHoursSinceResponseDate — is making it into the database, even though I have marked the class as Computed. I have also tried None. I understand from reading the EF documentation that this DatabaseGeneratedOption will still create a column in the database; I have been following posts such as this one that have lots of votes, but in reality, I don't think this is the solution.
How to I prevent a computed property in the model from making it into the DB? Another post suggests creating the migration and commenting out the field in the migration file created but this is very smelly and there's no way I'd get away with this!
Found it: [NotMapped]
Thanks anyway!
Related
We are currently re-writing our application and we have hundreds of tables and each of them has a CreatedById and ModifiedById and each of these has a foreign key to our users table, around 411 FKey / Nav properties to that table.
We use DevForce and EF for our DB access / entity management and during some testing of migration from our current application to this new one we are getting errors / stack overflows in the serializer and / or extremely long load times (5 seconds for 2000 entities).
I created a test app that had the same number of tables but removed all 411 of those FKeys and it dropped the load to under a second and the serialization errors also went away.
The issue I now have is I do actually need to get to the users table from a number of other entities using dot navigation / nav props so I was wondering if anyone knows how to add these to the buddy class via code.
I have googled and did find an old DevForce forum post that mentions something about some sample code to do this but there was no link to the actual sample.
If anyone has any ideas / suggestions I would really appreciate it.
Thanks in advance
I'm curious why you're seeing the serialization errors and poor load time. If you have the time, please open a support case at the DevForce support site with additional information so we can take a look at it.
The simplest approach to adding hand-coded navigation properties is to use the fact that the entity classes are partial classes. The "buddy" class is intended more to provide overrides for property attributes so isn't a good fit here.
To hand-code a navigation property, a simple example (without validation) could look something like this:
public partial class Customer {
private User _creationUser;
public User CreationUser {
get {
if (_creationUser == null) {
var query = new EntityKeyQuery(new EntityKey(typeof(User), this.CreatedById));
_creationUser = this.EntityAspect.EntityManager.ExecuteQuery(query).Cast<User>().FirstOrDefault();
}
return _creationUser;
}
set {
_creationUser = value;
this.CreatedById = _creationUser.UserId;
}
}
}
The problem here is that you have hundreds of entity classes which need these properties, so implementing these on a base entity class which your other entities extend would be a good idea. The DevForce Resource Center has more information on using a base entity class.
Another option is to override the template generation to generate custom properties on each entity. The DRC also has some information on this.
The entity model I'm working on is structured with inheritence as per:
public abstract class Line {}
public class WooLine : Line{
public bool wooProperty{ get; set; }
}
public class BooLine : Line
These are both stored in the database in the table Line. And in the database the column wooProperty is NOT NULL and default value (0).
These are maintained in a web app written with Knockout & Breeze. When working with BooLine trying to create a new entity, it throws an exception that I can't insert NULL into column wooProperty.
I set up a profile to trace the query, and it appears that since it's mapped to the Line table, during the Insert EntityFramework reads up all the properties and tries to actually insert NULL into the wooProperty, since it's not present in the Boo model. I'm moderately upset that EF is actively trying to insert NULL to a property I'm not working with...
Anyway. I can't move the wooProperty to the Line model - it belongs in the WooLine model. I'm hoping to solve it by either modifying the metadata in Breeze or forcing the wooProperty onto the saveChanges data. But I can't get breeze to recognize the property in the metadata. I've tried to run
metadataStore.registerEntityTypeCtor(
'BooLine', function () {
this.wooProperty = false;
});
Which almost works - but Breeze maps it as __unmapped value and as such isn't recognized after being recieved by EntityFramework.
I also started playing around with overriding the EFContextProvider and overriding BeforeSaveEntity. Entity is ReadOnly of type BooLine, and I can clearly see WooProperty in the UnmappedProperties, but I have no idea where to go from there... Any ideas?
TLDR in a way; Want to 'trick' entity framework into thinking an unmapped value is mapped when creating an entity.
To summarize my comments I would recommend one of the following:
make your model use TPT inheritance so there is no wooProperty column in the Line table, but in the inherited WooLine table
change your wooProperty column to be nullable and mark the wooProperty property in your entity class as [Required] and let EF take care of reading only "valid WooLines" - this should work if there is also a valid discriminator column for EF to use
EF Core has a "code first mentality" by default, i.e. it is supposed to be used in a code-first manner, and even though database-first approach is supported, it is described as nothing more than reverse-engineering the existing database and creating code-first representation of it. What I mean is, the model (POCO classes) created in code "by hand" (code-first), and generated from the database (by Scaffold-DbContext command), should be identical.
Surprisingly, official EF Core docs demonstrate significant differences. Here is an example of creating the model in code: https://ef.readthedocs.io/en/latest/platforms/aspnetcore/new-db.html And here is the example of reverse-engineering it from existing database: https://ef.readthedocs.io/en/latest/platforms/aspnetcore/existing-db.html
This is the entity class in first case:
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
and this is the entity class in second case:
public partial class Blog
{
public Blog()
{
Post = new HashSet<Post>();
}
public int BlogId { get; set; }
public string Url { get; set; }
public virtual ICollection<Post> Post { get; set; }
}
The first example is a very simple, quite obvious POCO class. It is shown everywhere in the documentation (except for the examples generated from database). The second example though, has some additions:
Class is declared partial (even though there's nowhere to be seen another partial definition of it).
Navigation property is of type ICollection< T >, instead of just List< T >.
Navigation property is initialized to new HashSet< T >() in the constructor. There is no such initialization in code-first example.
Navigation property is declared virtual.
DbSet members in a generated context class are also virtual.
I've tried scaffolding the model from database (latest tooling as of this writing) and it generates entities exactly as shown, so this is not an outdated documentation issue. So the official tooling generates different code, and the official documentation suggests writing different (trivial) code - without partial class, virtual members, construction initialization, etc.
My question is, trying to build the model in code, how should I write my code? I like using ICollection instead of List because it is more generic, but other than that, I'm not sure whether I need to follow docs, or MS tools? Do I need to declare them as virtual? Do I need to initialize them in a constructor? etc...
I know from the old EF times that virtual navigation properties allow lazy loading, but it is not even supported (yet) in EF Core, and I don't know of any other uses. Maybe it affects performance? Maybe tools try to generate future-proof code, so that when lazy-loading will be implemented, the POCO classes and context will be able to support it? If so, can I ditch them as I don't need lazy loading (all data querying is encapsulated in a repo)?
Shortly, please help me understand why is the difference, and which style should I use when building the model in code?
I try to give a short answer to each point you mentioned
partial classes are specially useful for tool-generated code. Suppose you want to implement a model-only derived property. For code first, you would just do it, wherever you want. For database first, the class file will be re-written if you update your model. So if you want to keep your extension code, you want to place it in a different file outside the managed model - this is where partial helps you to extend the class without tweaking the auto-generated code by hand.
ICollection is definitely a suitable choice, even for code first. Your database probably won't support a defined order anyway without a sorting statement.
Constructor initialization is a convenience at least... suppose you have either an empty collection database-wise or you didn't load the property at all. Without the constructor you have to handle null cases explicitely at arbitrary points in code. Whether you should go with List or HashSet is something I can't answer right now.
virtual enables proxy creation for the database entities, which can help with two things: Lazy Loading as you already mentioned and change tracking. A proxy object can track changes to virtual properties immediately with the setter, while normal objects in the context need to be inspected on SaveChanges. In some cases, this might be more efficient (not generally).
virtual IDbSet context entries allow easier design of testing-mockup contexts for unit tests. Other use cases might also exist.
i have some questions of how to use the Entity Framework in an enterprise application.
First of all, i work with ADO.NET for many years now and i use objects to reflect the data that i get from the database provider.
Every time i want to change something or insert something into the database.
I just call a Save() method and get the job done.
Every object has a DatabaseManager that manage the queries to the DataAccess layer.
For example
public class Article{
public int ID{get;set;}
public string Title{get;set;}
.....
public bool Save(){
if(this.ID == -1){
return new ArticleDatabaseManager().InsertArticle(this);
}else{
return new ArticleDatabaseManager().UpdateArticle(this);
}
}
}
public ArticleDatabaseManager : DatabaseManager
{
...ADO.NET code
}
I don't know if i have to use the same architectur or change all the way i use this objects in my application.
I thought if i create something like the above i can do something like this :
public class Article{
public int ID{get;set;}
public string Title{get;set;}
.....
public bool Save(){
if(this.ID == -1){
return new ArticleDatabaseManager().InsertArticle(this);
}else{
return new ArticleDatabaseManager().UpdateArticle(this);
}
}
}
In the Each DatabaseManager implements some Link To Entities or even EntitySQL to do the same job like the old DatabaseManager does.
Fill the Business models with the values that i from the Entity Objects.
Then i could work with the Business as before and just any time i want to do some changes i communicate via EntityFramework to the Database.
Sould i implement something like the above?
Sould i just inherit the previous business objects to the entity objects?
EX :
public class Article : ArticleEntity
{
//some properties for validation etc
}
Sould i use something completely different?
I Just Don't knwo:/
I have no experience with other ORM. Just mine hand written "ORM" System.
Thank you very much.
I'm sorry for my lack of English and i know that i ask too much in a single question...
But moving from one technology to an other for a dinosaur like me is like i change Country:/
Did you at least try to use some EF tutorial? If not it is time to do that because we cannot explain you everything about EF in single answer (even in multiple - that is not purpose of SO to replace tutorials and learning materials). That should give you pretty clear answer about all your stuff related to your database managers.
In general what you did till know is very close to Active record pattern. If your objects also has static methods used to retrieve object from database it is Active record pattern. When using EF you usually don't use this pattern and you don't need any database manager. EF is build around class which is called context and this context works as your database manager for all entities you are using. It is possible to add saving and retrieval methods to entities but because it breaks separation of concerns and it makes your entities heavily dependent on EF and persistence (trend is to make them completely independent = POCO) it is usually not used.
Don't derive any custom class from entity. EF will not be able to use your derived type. Use entity mapped in EF as your class and add all custom properties and methods directly to this class (you can even create that class from scratch if you don't want to use code generators). In case of generated entities you can add custom code in partial classes. If you don't use EF entity as your object you will have to manually handle conversion from one to other (or use some tool like AutoMapper).
EF is not able to work with XML column - it will handle it as string. Especially if you plan to use these data for some ordering or filtering and if they have fixed structure you should model them as separate tables / entities. If it is really just structured content (with dynamic structure) you can use it as XML string.
Just another question about custom extended properties in Entity Framework entities.
Entity model is quite simple in general. Of course in reality it is more complicated, but just for simplyfing I am not pasting all the generated code, just classes and needed properties.
So, I have the entity classes:
partial class Calibration
{
public string Identifier {get;set;}
public Device CalibratedDevice {get;set;}
}
partial class Device
{
public string Name {get;set;}
public ModelGroup ModelGroup {get;set;}
}
partial class ModelGroup
{
public Model[] Models {get;set;}
}
partial class Model
{
public Name {get;set;}
}
And I need to extend Calibration class with additional calculated property in another file.
partial class Calibration
{
public string ModelGroupName {get;set;}
}
This property is calculated like this:
string.Join(" / ", CalibratedDevice.ModelGroup.Models.Select(m => m.Name));
And finally I need to sort ObjectSet of Calibration entities by this calculated property.
Of course, code like
Calibrations.OrderBy(c => c.ModelGroupName)
will not work with throwing an exception, because EF cannot translate ModelGroupName property to database.
Of course, I know the easiest way to do it:
Calibrations.AsEnumerable().OrderBy(c => c.ModelGroupName)
And of course, it doesn't works for me, I don't want to load all the objects from data storage and sort them in linq because I need only a small piece of the whole ordered object set.
I know the approach with storing calculation lambdas instead of properties and passing it to OrderBy method, but it doesn't works either because I have more complex calculation logic than simple a + b.
For example
partial class Calibration
{
public static Expression<Func<Calibration, string>> ModelGroupName
{
get
{
return c => string.Join(" / ", c.CalibratedDevice.ModelGroup.Models.Select(m => m.Name));
}
}
}
Calibrations.OrderBy(Calibration.ModelGroupName)
will throw an Exception because EF cannot thanslate string.Join method to database.
I worked with the first version of EF and this annoying method-translation mechanism was a disaster. And now after few years of EF evolution this problem exists and I can found any suitable solution.
So, please, suggest the ways to organize IQueryable EF sorting by custom properties with calculation logic witch is not directly translated to SQL.
Thanks for replies.
You can map SQL functions to CLR functions in Entity Framework.
Here's a tutorial on how it is done:
http://blogs.microsoft.co.il/blogs/gilf/archive/2009/05/28/entity-sql-user-defined-functions-in-entity-framework-4.aspx
Please let me know if you need further help.
EF converts IQueryable objects into SQL statements that run on a db. You're asking if EF can translate arbitrary C# code into SQL - no, it can't.
It might be possible to construct a query that returns the right result set, which your custom properties can use - it depends on the logic.