custom code generation strategy for friendly navigation property - c#

I'm doing a DB-First generation of a DbContext and POCO objects with EF6 and having the same issues as many others re the navigation property names being unhelpful in describing relationships to other tables.
e.g If a Person has a Home and Work address, it would be reflected in the object as
public class Person {
public virtual DbSet<Address> Address;
public virtual DbSet<Address> Address1;
}
This question is on the right track for EF5, however neither the tool nor the code solution supports the t4 template generated by EF6.
Improve navigation property names when reverse engineering a database
What's the easiest way I can replace the above with
public class Person {
public virtual DbSet<Address> Home;
public virtual DbSet<Address> Work;
}
AND be able to regenerate the edmx file when I need to from scratch (i.e manually modifying 100 tables via the vs2013 GUI is not what I'm looking for).
I've looked around the forums and have started using the debug T4 Template tool but hoping there is a easier out than DIY.

If you don't need edmx, then you can remove it at all and reverse your database into Code First using EF Power Tools. After that use any tool that will help with property renames e.g Resharper

Related

What is a proper way of writing entity POCO classes in Entity Framework Core?

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.

Bind database to Collection c#

I am developing a data intensive app in C# and need some advice on the best method to manage my data. My application will use a number of related tables with a lot of movement backwards and forwards between the app and the database.
My question is, what method would be best to handle data? All of my data fields are controlled within their own classes and collections, so hence, the question is really more of a case of what is the best method to bind my collections and objects to the database.
Should I manually create my own SQL connections / SQL Insert / Update queries, or is there another way to do this? For instance is it possible in Visual Studio to easily create a strongly typed data layer that will automatically look after Inserts / Updates / Deletes etc?
Many thanks
Q. For instance is it possible in Visual Studio to easily create a strongly typed data layer that will automatically look after Inserts / Updates / Deletes etc?
Entity Framework sounds like something you're looking for. There is, of course, some setup involved. With most web projects, Entity Framework is automatically added, and if not you can always add it via NuGet package manager.
EntityFramework binds your models to a Database through the DbContext object, and Code First will even generate a database if one does not exist based on your models (if one does exist and the models change, you might have to migrate: More reading). I will be taking that approach (you can later change the following code to a connection string to a live DB).
First, you need to tell your application what database to use (whether it exists or not), and this can be done in the Web.Config file (not the only approach).
Web.Config
<configuration>
....
<connectionStrings>
<add name="ConnectionStringName" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\DATABASENAME.mdf;Initial Catalog=DATABASENAME;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>
NOTE - this connection string will only work in VS2015. For previous versions, use:
Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\DATABASENAME.mdf
More reading on configuring Entity Framework
Now, we can use "ConnectionStringName" to connect our context.
The Context class will have to inherit from the DbContext object, and we will pass this connection string name to the base constructor (DbContext exists in the System.Data.Entity namespace). I will use two generic models that look identical (ModelA ModelB) --
ModelA and ModelB
using System.ComponentModels.DataAnnotations;
public class ModelA
{
public int Id { get; set; }
[Required(ErrorMessage="You need to enter a name!")]
[StringLength(40)]
public string Name { get; set; }
}
NOTE - I'm using DataAnnotations (Required, StringLength) - these are really cool and can be very useful when implementing CRUD operations on your model.
ALSO -- Entity Framework will automatically make properties that are named: Id (or any case form) or ModelNameId the primary key. There are ways to override this.
More reading on DataAnnotations
You can even create your models with relationships in mind. If ModelA will have a one-to-many relationship with ModelB, you can reflect this relationship in code:
public virtual ICollection<ModelB> ModelBs {get; set;}
More reading on creating relationships
We will now map your models to tables using the DbSet collection. Here's how that looks:
using System.Data.Entity;
using YourProject.Data.Models;
namespace YourProject.Data.DAL
{
public class YourContext : DbContext
{
public YourContext() : base("ConnectionStringName")
{
}
public DbSet<ModelA> ModelAs { get; set; }
public DbSet<ModelB> ModelBs { get; set; }
}
}
Database Initialization Strategies - for seeding your database with data on creation.
More reading on configuring the context
I will never be able to detail everything you can do - but here are a few short examples:
Q. What does all this do?
You now have a strongly-typed object connected to your database. It's as simple as creating a new Context object:
YourContext yourContext = new YourContext();
Retrieving a whole table is as easy as:
IEnumerable<ModelA> modelAs = yourContext.ModelAs;
or finding a row by Id
ModelB modelB = yourContext.ModelBs.Find(id);
Say you grabbed modelB and want to update it. It's as easy as:
modelB.Name = "Here's the new name";
yourContext.Entry(modelB).State = EntityState.Modified;
yourContext.SaveChanges();
Adding:
yourContext.ModelAs.Add(newModel);
Removing:
yourContext.ModelBs.Remove(modelB);
REMEMBER Add/Update/Delete methods will ALL require a call to SaveChanges(); from the Context. Otherwise they will be discarded.
Of course, this is probably the most basic rundown of Entity Framework available. To see more of it in action check out these tutorials:
WebForms with Entity Framework - Wingtip Toys
MVC with Entity Framework - Contoso University
Hope this may be of assistance for someone.

Adding a new table to model (edmx) without updating the other models in Database First Entity Framework MVC application

I have an MVC 5 application that uses Entity Framework 6 Database First approach.
So far It is working well, but I have come across an unwanted behaviour.
If I select 'Update Model From Database', select the 'Add' Tab, and then select the Tables or Views I would like to add and click Finish, it adds the Tables and/or Views I specified no problem.
However, the unwanted behaviour is that, even though I didn't select the Refresh Tab, it seems every single model is automatically being refreshed.
This means all my custom Attributes on my models are being removed.
Is there any way to specify to only add the specified Tables or Views without refreshing all models, or if it refreshes all models, to retain the Attributes I have specified?
Visual Studio information: Microsoft Visual Studio Professional 2013
Version 12.0.40629.00 Update 5
Microsoft .NET Framework
Version 4.5.51650
Installed Version: Professional
Is this a bug or intended use?
Thanks
Neill
In order to modify autogenerated classes it's advised to use a partial class, that way your changes won't be lost when the class is refresh / generated again.
Simple example of a class and a partial class expanding on its attributes and methods
// Assume this is autogenerated by EntityFramework
public class Book {
public int Id {get; set;}
public string Title {get; set;}
}
// In a different file.cs
public partial class Book {
[Required]
public string Author {get; set;}
public override ToString(){
// Some code goes here
}
}
In that example, if EntityFramework generates a new Book model, the changes you've done to that model via the partial class won't be lost at all.
Check out this article for more information on partial classes and this question for more info on the advantages of using partial classes.
Edit: if you need to add attributes to existing properties of your autogenerated class this answer might help you out as well.
You really need to use partial classes so that you can refresh the edmx to your heart's content.
look here for a great tutorial on the subject.

Methods for breaking apart a large DbContext with many relationships

A project I'm working on has DbContext that tracks a lot of different Entities. Due to the large number of relationships involved, it takes a long time to query from the context the first time around while it generates its views. In order to reduce the startup time, and better organize contexts into functional areas, I'm looking for ways to split it apart.
These are some methods I've tried so far, and problems I've seen with them:
Create a new smaller Context with a subset of DbSets from the huge Context.
This doesn't help, since EF seems to crawl through all the navigation properties and include all related entities anyway (according to LINQPad at least, which shows all the entities related to the Context when it's expanded in the connection panel). We have a few top-level entities that are far reaching, so there are very few subsets that can be fully isolated without removing navigation properties and doing a good amount of refactoring.
Split Entities into classes that include navigation properties, and ones that are just db fields, like so:
public class PersonLight
{
public int Id { get; set; }
public string Name { get; set; }
public int JobId { get; set; }
}
public class Person : PersonLight
{
public Job Job { get; set; }
}
public class ContextLight : DbContext
{
public virtual DbSet<PersonLight> People { get; set; }
}
No dice here as well. Even though Person isn't used at all, EF (or again, possibly just LINQPad) includes Person despite the fact that it can't be used. I assume this is because EF supports inheritance patterns, so it ends crawling related entities in this direction as well.
Do the same as #2, but with PersonLight and Person in different projects (or use partial classes in different projects). This is the best option so far, but it would be nice to have PersonFields right next to Person for easy reference.
So my questions are:
Are there any better ways to do this that I'm missing?
Why, in #3, does putting them in different projects seem to separate them enough that EF doesn't try to include both? I've tried putting them in different namespaces, but that doesn't do the trick.
Thanks.
Options to speed things along:
Generated views
Bounded Contexts
Ironically IIS app pool only needs to generate the view once.
Command line based on my tests, generates the view each time.
Not sure what linqpad does.
BTW I didn't originally add this link since you tagged it EF6.
But in case others aren't on EF6. There are some performance improvements reported. More information here:
EF6 Ninja edition

Entity Framework (Database-First) multiple relations to same table naming conventions control

Let's suppose that we have this situation:
Tables in database:
Country (id, country_name), Person (id, login), CountryManager (id_country, id_person), CountryStakeholder (id_country, id_person)
If we had to create the model from the database, using Entity Framework Database-First, in VS we'd have a class like this:
class Country {
int id;
string country_name;
virtual ICollection<Person> Person1; // Navigation Properties
virtual ICollection<Person> Person2; // ---------||----------
}
I've simplified the code a lot, but hopefully you got the point.
Seems that when Entity Framework deals with foreign keys it creates generic Navigation Properties. Is there a possibility to control how Navigation Properties are created by name? Person1, Person2 isn't very explainatory, unfortunately.
In VS you can do this with the GUI.
If you show Model Browser then navigate down the tree to:
YourEntityModel > Entity Types > Country
then right-click on the "Person1" Navigation Property and select "Properties" you can then change the name of the navigation property name to whatever you like:
Just change the name, save changes and your done...
(Actually there are lots of ways to get to the Navigation Property properties window - you cn right click on it in the model diagram too)
From the entry "Working with Inverse Navigation Properties" from the book "Programming Entity Framework: Code First":
You can add configuration (using Data Annotations or the Fluent API)
to present this information to the model builder. With Data
Annotations, you’ll use an annotation called InverseProperty. With the
Fluent API, you’ll use a combination of the Has/With methods to
specify the correct ends of these relationships.
You can place the annotations on either end of the relationship (or
both ends if you want). We’ll stick them on the navigation properties
in the Lodging class (Example 4-10). The InverseProperty Data
Annotation needs the name of the corresponding navigation property in
the related class as its parameter.
Example:
[InverseProperty("PrimaryContactFor")]
public Person PrimaryContact { get; set; }
[InverseProperty("SecondaryContactFor")]
public Person SecondaryContact { get; set; }
I recommend using https://visualstudiogallery.msdn.microsoft.com/ee4fcff9-0c4c-4179-afd9-7a2fb90f5838
It allows more flexibility than any database generation thing I've seen.
I'm still working on solving my own problem, but this looks pretty promising. But, unlike the Default Code generation that EF provides, you can customize the mapping.
Like, in all the examples I've seen on renaming the navigation properties -- that alone won't be enough, because EF still needs to be mapped to use those navigation properties (you could hack it though, and have your User2 point to ModifiedByUser, for example).

Categories

Resources