I want to use EF code first to apply the existing database tables modeling.
Let's say I have three tables.
Project table. The primary key is ProjectId, it has other columns such as ProjectName, StartDate and EndDate etc.
Technology table. The primary key is TechnologyId, the other columns are technologyName, Note etc.
ProjectTechnologyLink. Link the two tables together. It has the Primary key ProjectId and TechnologyId also they are the foreign keys.
The sample data in ProjectTechnologyLink
ProjectId TechnologyId CreatedBy CreatedDate
25 3 One 2016-01-01
100 4 One 2016-01-01
100 8 Two 2016-01-01
Assume One project can have many technologies and one technology can exist in many projects.
The model classes are:
For Project:
public class Project
{
public int ProjectId {get;set;}
public string ProjectName {get;set;}
...
public ICollection<ProjectTechnologyLink> ProjectTechnologyLink
}
For Technology:
public class Technology
{
public Technology()
{
ProjectTechnologyLink = new HashSet<ProjectTechnologyLink>();
}
public int TechnologyId {get;set;}
public string TechnologyName {get;set;}
...
public ICollection<ProjectTechnologyLink> ProjectTechnologyLink {get;set;}
}
For ProjectTechnologyLink class.
public class ProjectTechnologyLink
{
public int ProjectId {get;set;}
public int TechnologyId {get;set;}
...
public Project Project {get;set;}
public Technology Technology {get;set;}
}
Then in OnModelCreating method.
modelBuilder.Entity<ProjectTechLink>(entity =>
{
entity.HasKey(e=> new {e.ProjectId, e.TechnologyId});
entity.ToTable("ProjectTechnology", "myscheme");
entity.HasOne(x=>x.Project)
.WithMany(p=>p.ProjectTechnologyLink)
.HasForeignKey(d=>d.ProjectId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_PROJECT_TECHNOLOGY_LINK_PID");
entity.HasOne(x=>x.Technology)
.WithMany(p=>p.ProjectTechnologyLink)
.HasForeignKey(d=>d.TechnologyId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_PROJECT_TECHNOLOGY_LINK_TID");
});
My question is
Is it right for the all code? Sometimes I saw people put some attributes before the properties in the class. But I don't have it.
Your code is very acceptable, and should serve you well, but lets review why there is a mix of Attributes and Fluent API out there.
The EF pipeline has three main points where we can inject database metadata (table configuration), these include:
Attribute Notation
Code First Conventions
Fluent Configuration API
The order above list also depicts the order that they are processed within the pipeline, internally the Attributes are meaningless to the DbContext until they are parsed by built in (or customised) Conventions, these conventions internally use the Fluent API to configure the DbContext.
Different scenarios call for and allow different mixes, generally in a Code First scenario Attribute Notation is preferred over heavy use of the Fluent API. However foreign key constraints that include cascading deletes or many to many relationships such as this are often expressed in Fluent API directly as the syntax can be a bit simpler as well as to ensure that no other conventions can overrule our expected implementation in the database.
Attribute notation allows your table schema to be mostly contained within the class definition, but still allows the application runtime to override the interpretations of these attributes by customising, or disabling built in conventions.
If your metadata can be expressed using attributes, then the entire specification of your schema becomes more concise, which is especially useful when presenting your code solutions online in examples where the structure and relationships are important to be shown. If your online example only needs to express the relationship, then those examples will often only use fluent notation.
- It makes for a heard to implement code example if you need express both the schema and relationship mapping separately.
If you use attribute notation, then your example can be expressed like this, and you will not need anything extra in OnModelCreating:
public class Project
{
[Key]
public int ProjectId { get; set; }
public string ProjectName { get; set; }
...
public virtual ICollection<ProjectTechnologyLink> ProjectTechnologyLink { get; set; } = new HashSet<ProjectTechnologyLink>();
}
NOTE: In the above Project class definition I have used an inline initializer for the ProjectTechnologyLink relationship, i find this style fits in well with Attribute Notation as the default value is now also defined in close proximity with the Property, when initializers are only only defined in the constructor it is easy to forget to include an init at all or it can be hard to find the init logic in code. Now a quick "Got To Definition" will reveal the default implementation as well as any database schema related attributes without having to lookup other resources.
public class Technology
{
public Technology()
{
ProjectTechnologyLink = new HashSet<ProjectTechnologyLink>();
}
[Key]
public int TechnologyId { get; set; }
public string TechnologyName { get; set; }
...
public virtual ICollection<ProjectTechnologyLink> ProjectTechnologyLink { get; set; }
}
public class ProjectTechnologyLink
{
[Key, Column(Order = 0)]
public int ProjectId { get; set; }
[Key, Column(Order = 0)]
public int TechnologyId { get; set; }
...
[ForeignKey(nameof(ProjectId))]
public virtual Project Project { get; set; }
[ForeignKey(nameof(TechnologyId))]
public virtual Technology Technology { get; set; }
}
virtual Navigation Properties:
In EF it is important to mark your navigation properties as virtual members. This will allow EF to implement lazy loading and perform other optimised implementation of those properties when it generates a wrapper class that inherits from your entity class. Even if you do not intend to support Lazy Loading, there are other scenarios where EF will wrap your class, and either way your data definition classes should not be concerned or aware of operational decision that can be made and changed at runtime depending on your context needs.
Conventions:
The previous example demonstrates pure attribute notation. It is very possible to replace the default Conventions with your own for defining primary and foreign keys. Meaning it is theoretically possible to not have any attributes or Fluent notation at all. I try to discourage a pure convention based approach because it makes it a bit harder to find the configuration in a large or distributed schema definition, which is also the same argument I use to discourage a pure Fluent API approach, attributes are the logical place to document the expected usage of a table or field.
Related
I`m in process of learning C# & .NET and EF (with aspnetboilerplate) and I came up with idea to create some dummy project so I can practice. But last 4 hour Im stuck with this error and hope someone here can help me.
What I create( well at least I think I create it correctly ) is 2 class called "Ingredient" and "Master"
I want to use it for categorize Ingredient with "Master" class.
For example ingredient like
Chicken breast
chicken drumstick
Both of them belong to Meat ( witch is input in "Master" database ) and here is my code
Ingredient.cs
public class Ingrident : Entity
{
public string Name { get; set; }
public Master Master { get; set; }
public int MasterId { get; set; }
}
Master.cs
public class Master : Entity
{
public string Name { get; set; }
public List<Ingrident> Ingridents { get; set; } = new();
}
IngridientAppService.cs
public List<IngridientDto> GetIngWithParent()
{
var result = _ingRepository.GetAllIncluding(x => x.Master);
//Also I try this but doesn`t work
// var result = _ingRepository.GetAll().Where(x => x.MasterId == x.Master.Id);
return ObjectMapper.Map<List<IngridientDto>>(result);
}
IngridientDto.cs
[AutoMap(typeof(IndexIngrident.Entities.Ingrident))]
public class IngridientDto : EntityDto
{
public string Name { get; set; }
public List<MasterDto> Master { get; set; }
public int MasterId { get; set; }
}
MasterDto.cs
[AutoMap(typeof(IndexIngrident.Entities.Master))]
public class MasterDto : EntityDto
{
public string Name { get; set; }
}
When I created ( for last practice ) M -> M relationship this approach with .getAllIncluding work but now when I have One -> Many it won`t work.
Hope someone will be able to help me or at least give me some good hint.
Have a nice day !
Straight up the examples you are probably referring to (regarding the repository etc.) are overcomplicated and for most cases, not what you'd want to implement.
The first issue I see is that while your entities are set up for a 1-to-many relationship from Master to Ingredients, your DTOs are set up from Ingredient to Masters which definitely won't map properly.
Start with the simplest thing. Get rid of the Repository and get rid of the DTOs. I'm not sure what the base class "Entity" does, but I'm guessing it exposes a common key property called "Id". For starters I'd probably ditch that as well. When it comes to primary keys there are typically two naming approaches, every table uses a PK called "Id", or each table uses a PK with the TableName suffixed with "Id". I.e. "Id" vs. "IngredientId". Personally I find the second option makes it very clear when pairing FKs and PKs given they'd have the same name.
When it comes to representing relationships through navigation properties one important detail is ensuring navigation properties are linked to their respective FK properties if present, or better, use shadow properties for the FKs.
For example with your Ingredient table, getting rid of the Entity base class:
[Table("Ingredients")]
public class Ingredient : Entity
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int IngredientId { get; set; }
public string Name { get; set; }
public int MasterId { get; set; }
[ForeignKey("MasterId")]
public virtual Master Master { get; set; }
}
This example uses EF attributes to aid in telling EF how to resolve the entity properties to respective tables and columns, as well as the relationship between Ingredient and Master. EF can work much of this out by convention, but it's good to understand and apply it explicitly because eventually you will come across situations where convention doesn't work as you expect.
Identifying the (Primary)Key and indicating it is an Identity column also tells EF to expect that the database will populate the PK automatically. (Highly recommended)
On the Master side we do something similar:
[Table("Masters")]
public class Master : Entity
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int MasterId { get; set; }
public string Name { get; set; }
[InverseProperty("Master")]
public virtual ICollection<Ingredient> Ingredients { get; set; } = new List<Ingredient>();
}
Again we denote the Primary Key, and for our Ingredients collection, we tell EF what property on the other side (Ingredient) it should use to associate to this Master's list of Ingredients using the InverseProperty attribute.
Attributes are just one option to set up the relationships etc. The other options are to use configuration classes that implement IEntityConfiguration<TEntity> (EF Core), or to configure them as part of the OnModelCreating event in the DbContext. That last option I would only recommend for very small projects as it can start to become a bit of a God method quickly. You can split it up into calls to various private methods, but you may as well just use IEntityConfiguration classes then.
Now when you go to fetch Ingredients with it's Master, or a Master with its Ingredients:
using (var context = new AppDbContext())
{
var ingredients = context.Ingredients
.Include(x => x.Master)
.Where(x => x.Master.Name.Contains("chicken"))
.ToList();
// or
var masters = context.Master
.Include(x => x.Ingredients)
.Where(x => x.Name.Contains("chicken"))
.ToList();
// ...
}
Repository patterns are a more advanced concept that have a few good reasons to implement, but for the most part they are not necessary and an anti-pattern within EF implementations. I consider Generic repositories to always be an anti-pattern for EF implementations. I.e. Repository<Ingredient> The main reason not to use repositories, especially Generic repositories with EF is that you are automatically increasing the complexity of your implementation and/or crippling the capabilities that EF can bring to your solution. As you see from working with your example, simply getting across an eager load through to the repository means writing in complex Expression<Func<TEntity>> parameters, and that just covers eager loading. Supporting projection, pagination, sorting, etc. adds even more boiler-plate complexity or limits your solution and performance without these capabilities that EF can provide out of the box.
Some good reasons to consider studying up on repository implementations /w EF:
Facilitate unit testing. (Repositories are easier to mock than DbContexts/DbSets)
Centralizing low-level data rules such as tenancy, soft deletes, and authorization.
Some bad (albeit very common) reasons to consider repositories:
Abstracting code from references or knowledge of the dependency on EF.
Abstracting the code so that EF could be substituted out.
Projecting to DTOs or ViewModels is an important aspect to building efficient and secure solutions with EF. It's not clear what "ObjectMapper" is, whether it is an Automapper Mapper instance or something else. I would highly recommend starting to grasp projection by using Linq's Select syntax to fill in a desired DTO from the models. The first key difference when using Projection properly is that when you project an object graph, you do not need to worry about eager loading related entities. Any related entity / property referenced in your projection (Select) will automatically be loaded as necessary. Later, if you want to leverage a tool like Automapper to help remove the clutter of Select statements, you will want to configure your mapping configuration then use Automapper's ProjectTo method rather than Map. ProjectTo works with EF's IQueryable implementation to resolve your mapping down to the SQL just like Select does, where Map would need to return everything eager loaded in order to populate related data. ProjectTo and Select can result in more efficient queries that can better take advantage of indexing than Eager Loading entire object graphs. (Less data over the wire between database and server/app) Map is still very useful such as scenarios where you want to copy values back from a DTO into a loaded entity.
Do it like this
public class Ingrident:Entity
{
public string Name { get; set; }
[ForeignKey(nameof(MasterId))]
public Master Master { get; set; }
public int MasterId { get; set; }
}
Using EF6 and .NET 4.6.1. I know this somewhat is a duplicate (I've looked at this stack overflow post) but hear me out. My case is different and I have tried to get it to work using their solutions with mine but it didn't work. So no this isn't actually a duplicate. It's another issue altogether and I haven't found a post that really helps me on this topic.
I am trying to map relationships between 3 models; Employee, Position and Employment. I want a one-to-many between Employment and Position (employments map to one position) and a one-to-one between Employment and Employee.
public class Employment
{
public int EmploymentID { get; set;}
...
public Position Position { get; set; }
public Employee Employee { get; set; }
}
public class Position
{
public int PositionID { get; set;}
...
[InverseProperty("Position")]
public ICollection<Employment> Employments { get; set; }
}
public class Employee
{
public int EmployeeID { get; set;}
...
[InverseProperty("Employee")]
public Employment Employment { get; set; }
}
However, when I try to run this with DbContext automapping, it fails and says it can't find the relationships. I've tried multiple combinations of data annotations like setting inverseproperties and foreignkey("____ID") on some of them but haven't been able to get it to work.
I did also try adding virtual keywords in for some of the but that didn't do anything either.
I'd rather not use FluentAPI as I want to let the auto mapper do as much as possible with this. It's not complicated a problem enough to warrant manually mapping it with FluentAPI (At least in my opinion it isn't. Maybe I'm wrong).
What data annotations do I need? I've looked at this stack overflow post and various articles on entityframeworktutorial.net trying to apply their solutions to my case. But haven't gotten anything to work.
The failing line is here:
using (EmploymentContext ctx = new EmploymentContext())
{
Position pos = new Position()
{
PositionID=1,
Name="General Manager"
};
ctx.Positions.Add(pos); // Failing here
ctx.SaveChanges();
}
and the error message is:
'Unable to determine the principal end of an association between the types 'Ianmann.Hr.DataAccess.Employment.Employee and Ianmann.Hr.DataAccess.Employment.Employment. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.'
I don't know why you insist on using data annotations. Everything you can do with data annotation can be done with the Fluent API, but the opposite is not true. Also, and especially with relationships, the data annotations are not intuitive and error prone.
In the concrete case the problem is with the one-to-one relationship (btw, the error message should contain that information). It's because EF cannot determine the principal and the dependent of the relationship when the ends of the relationship are both optional (as in your case) or both required. So one way to resolve it is to mark the principal by making the navigation property required:
public class Employment
{
public int EmploymentID { get; set; }
...
public Position Position { get; set; }
[Required] // <--
public Employee Employee { get; set; }
}
The InverseProperty is redundant (not needed) in this case.
The same can be achieved more intuitively with fluent API:
modelBuilder.Entity<Employment>()
.HasRequired(e => e.Employee)
.WithOptional(e => e.Employment);
But please note that while either way will resolve the issue in question, the resulting design will be the so called Shared Primary Key association, where EmploymentID is both PK and also FK to Employee. In case you want a separate FK property / column, then fluent API is a must as it cannot be done via data annotations:
modelBuilder.Entity<Employment>()
.HasRequired(e => e.Employee)
.WithOptional(e => e.Employment)
.Map(m => m.MapKey("EmployeeID"));
I have been searching the web for weeks in hope of finding a solution to an issue I'm having when using the .NET Identity framework to create my database.
One of the closest related issues i found is this: Customised IdentityUserRole primary key
However I am using automatic migrations, in order to avoid manually specifying Up and Down methods.
What I'm trying to achieve is to have an additional primary key in my UserRoles table, which is derived from IdentityUserRoles and the implementation looks like this:
public class UserRole : IdentityUserRole
{
[Key, ForeignKey("Company")]
public string CompanyId { get; set; }
public Company Company { get; set; }
}
My OnModelCreating method looks like this:
...
public DbSet<UserRole> UserRolesExt { get; set; }
...
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>().ToTable("Users");
modelBuilder.Entity<IdentityUserRole>().ToTable("UserRoles");
// Failed attempt to make property a primary key below:
modelBuilder.Entity<UserRole>().HasKey(ur => ur.CompanyId).ToTable("UserRoles");
modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogins");
modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaims");
modelBuilder.Entity<IdentityRole>().ToTable("Roles");
}
However, the table ends up looking like this:
http://i.imgur.com/n0dne7O.png
One thing that got me puzzled is the fact that it is also set as a nullable type, but I have a feeling that is refering to my custom Company class which only contains primitive data types.
The reason why I want this 3-way-relationship for this entity is that my system will contain several users in several companies, where each user can be a member of more than one company, and hereby also individual roles of that user within the given company.
I would if possible, very much like to avoid making my own UserStores and RoleStores etc., which is some of the solutions I've found, since I would like to keep it simple so to say.
An example from one of my classes that does not derive from Identity classes looks as follows and works just as intended:
public class UserModule
{
[Key, ForeignKey("User"), Column(Order = 0)]
public string UserId { get; set; }
public User User { get; set; }
[Key, ForeignKey("Module"), Column(Order = 1)]
public string ModuleId { get; set; }
public Module Module { get; set; }
}
I have tried fiddling around with various versions of my data annotations in my UserRole class but without any luck. Is there really no way of extending this UserRole class to have an additional primary key, without having to make major customizations?
It should also be noted that if I simply edit the database manually after creation, I am able to make all three properties primary keys and the table works as intended. But I would very much like to know how I can make it work properly so to say.
Any help would be greatly appreciated!
If I understand correctly, you want to add an additional column to the IdentityUserRole class and have that column be part of the primary key. To do so, you have to slightly modify your OnModelCreating method as follows:
modelBuilder.Entity<UserRole>()
.ToTable("UserRoles")
.HasKey(r => new { r.UserId, r.RoleId, r.CompanyId })
.HasRequired(r => r.Company).WithMany();
This code essentially redefines the primary key to also include the CompanyId column and then makes it a required field.
You should also remove the [Key, ForeignKey("Company")] attributes from the CompanyId property, to prevent the annotations from interfering with the fluent syntax. I don't think the modelBuilder.Entity<IdentityUserRole>().ToTable("UserRoles"); line is necessary too, you could try removing it.
I would like to know what rules Entity Framework follows in regards to the naming/generation of navigation properties. I have observed several scenarios which don't seem to make sense so I was wondering if anyone knows exactly how these work.
Scenario 1:
public class Post
{
public int Id { get; set; }
public User Author { get; set; }
}
Generates
ie. by default navigation properties generate FKs named [PropertyName]_Id
Scenario 2:
It makes sense that if EF generates properties such of the format [PropertyName]_Id when you manually specify a FK Id it will follow the same rules however:
public class Post
{
public int Id { get; set; }
public int? Author_Id { get; set; }
public User Author { get; set; }
}
Generates
As you can see this doesn't automatically register as a nav property.
Scenario 3:
If it doesn't work for Scenario 2 why does it work for an alternate naming convention?
public class Post
{
public int Id { get; set; }
public int? AuthorId { get; set; }
public User Author { get; set; }
}
Generates
What are the rules around navigation property detection and generation?
That is expected behavior and it is based on two different conventions based by EF
In the first example you are using Independent association where your entity doesn't have FK property. EF will create FK in the database using simple pattern: NameOfNavigationProperty_NameOfRelatedPK This convention follows traditional database naming.
In the second example you defined property with the same name as FK used by EF. EF detected this and added 1 to its generated FK. The reason why your property is not used as FK is the second convention which searches for FK properties. This convention expects that FK property will have this name (conventions follows traditional .NET naming):
NameOfNavigationPropertyNameOfRelatedPK provided by NavigationPropertyNameForeignKeyDiscoveryConvention
NameOfRelatedTypeNameOfItsPK provided by TypeNameForeignKeyDiscoveryConvention
NameOfRelatedPK provided by PrimaryKeyNameForeignKeyDiscoveryConvention
In the last example you correctly defined FK property and EF detected it so it uses Foreign key association.
In addition to #Ladislav Mrnka's answer above, you can find a detailed reference of the entity framework default conventions here:
http://msdn.microsoft.com/en-us/library/system.data.entity.modelconfiguration.conventions(v=vs.103).aspx
I am looking into migrate a large project to Entity Framework 4.0 but am not sure if it can handle my inheritance scenario.
I have several projects that inherit from an object in the “main” project. Here is a sample base class:
namespace People
{
public class Person
{
public int age { get; set; }
public String firstName { get; set; }
public String lastName { get; set; }
}
}
and one of the sub-classes:
namespace People.LawEnforcement
{
public class PoliceOfficer : People.Person
{
public string badgeNumber { get; set; }
public string precinct { get; set; }
}
}
And this is what the project layout looks like:
People - People.Education - People.LawEnforcement http://img51.imageshack.us/img51/7293/efdemo.png
Some customers of the application will use classes from the People.LawEnforcement and other users will use People.Education and some will use both. I only ship the assembles that the users will need. So the Assembles act somewhat like plug-ins in that they add features to the core app.
Is there anyway in Entity Framework to support this scenario?
Based on this SO question I'm think something like this might work:
ctx.MetadataWorkspace.LoadFromAssembly(typeof(PoliceOfficer).Assembly);
But even if that works then it seams as if my EDMX file will need to know about all the projects. I would rather have each project contain the metadata for the classes in that project but I'm not sure if that is possible.
If this isn't possible with entity framework is there another solution (NHibernate, Active Record, etc.) that would work?
Yes this is possible, using the LoadFromAssembly(..) method you've already found.
... but it will only work if you have an specialized model (i.e. EDMX) for each distinct type of client application.
This is because EF (and most other ORMs) require a class for each entity in the model, so if some clients don't know about some classes, you will need a model without the corresponding entities -- i.e. a customized EDMX for each scenario.
To make it easier to create a new model for each client application, if I was you I'd use Code-Only following the best practices laid out on my blog, to make it easy to grab only the fragments of the model you need actually need.
Hope this helps
Alex
Alex is correct (+1), but I'd strongly urge you to reconsider your model. In the real world, a police officer is not a subtype of a person. Rather, it's an attribute of that person's employment. I think programmers frequently tend to over-emphasize inheritance at the expense of composition in object oriented design, but it's especially problematic in O/R mapping. Remember that an object instance can only ever have one type. When that object is stored in the database, the instance can only have that type for as long as it exists, across multiple application sessions. What if a person had two jobs, as a police officer and a teacher? Perhaps that scenario is unlikely, but the general problem is more common than you might expect.
More relevant to your question, I think you can solve your actual problem at hand by making your mapped entity model more generic, and your application-specific data projections on the entities rather than entities themselves. Consider entities like:
public class JobType
{
public Guid Id { get; set; }
// ...
}
public class Job
{
public JobType JobType { get; set; }
public string EmployeeNumber { get; set; }
}
public class Person
{
public EntityCollection<Job> Jobs { get; set; }
}
Now your law enforcement app can do:
var po = from p in Context.People
let poJob = p.Jobs.Where(j => j.JobType == JobType.PoliceOfficerId).FirstOrDefault()
where poJob != null
select new PoliceOfficer
{
Id = p.Id,
BadgeNumber = poJob.EmployeeNumber
};
Where PoliceOfficer is just a POCO, not a mapped entity of any kind.
And with that you've achieved your goal of having a common data model, but having the "job type specific" elements in separate projects.