Can I specify global mapping rules in Entity Framework Code First? - entity-framework

I'm building an app in ASP.NET MVC 4 using Entity Framework Code First, and for simplicity I'm inheriting all models that will be stored in the database from a BaseEntity that has a Guid, a DateCreated, a LastEditDate and a other useful properties like that. Now, I know that I can tell EF to map these inherited properties like so:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().Map(m =>
{
m.MapInheritedProperties();
});
modelBuilder.Entity<Product>().Map(m =>
{
m.MapInheritedProperties();
});
}
It seems silly to have to do this for every item, though. Is there a way I can apply this rule to all entities in one?

It has been stated correctly that it's not necessary to do global mapping in this specific case, because EF will map the properties for each individual type as long as you don't make BaseEntity part of the model.
But your question title is stated more generally and yes, it is possible to specify global mapping rules if you configure the mappings by EntityTypeConfigurations. It could look like this:
// Base configuration.
public abstract class BaseMapping<T> : EntityTypeConfiguration<T>
where T : BaseEntity
{
protected BaseMapping()
{
this.Map(m => m.MapInheritedProperties()); // OK, not necessary, but
// just an example
}
}
// Specific configurations
public class UserMapping : BaseMapping<User>
{ }
public class ProductMapping : BaseMapping<Product>
{ }
public class TempModelsContext : DbContext
{
// Add the configurations to the model builder.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new UserMapping());
modelBuilder.Configurations.Add(new ProductMapping());
}
// DbSets
...
}
Notes:
In Entity Framework 6 (for .Net framework) has custom code first conventions by which many global mapping rules can be configured.
Entity Framework core has even more extensive tools for configuring global mappings.

Such a mapping - called Table-Per-Concrete-Type (TPC) inheritance mapping - only makes sense if you really want to leverage polymorphism, for example if you want to load a list of say 10 BaseEntity objects and expect that the actual type gets materialized so that the list contains 3 User entities and 7 Product entities.
Would such a query ever have any business relevance in your application? Looking at your BaseEntity I can only see that querying all objects that - for example - have been created at a specific date, no matter which type the object has (if it's derived from BaseEntity), could be useful. Do you need that? Also keep in mind how complex such a query would be. The SQL must query for almost all tables in your database and then union the result.
I would use inheritance mapping only if it has a real business meaning (for instance: Person which has meaningful properties like address, phone, email, etc. on its own and Employee that is derived from Person and adds a Salary and HiredDate property, etc.).
In your case I would use the BaseEntity only as a base type of your entity classes and don't specify any mapping at all for this class. EF will still map the inherited properties, but as part of the User and Product entity, etc., not as its own entity. I wouldn't even call it "Base Entity" but ... I don't know... maybe EntityBase (meaning: the base (class) of all entities, but not an entity itself).

Related

Entity Framework model first: create UNIQUE constraint programmatically

I am trying to add a UNIQUE constraint to the "Username" property of my "UserAccount" entity/class. With code-first, that would be no problem, but for model-first, I can't find anything on how to achieve that.
The designer does not support this feature. I cannot use annotations because the entity classes are auto-generated. I cannot use Fluent API because the OnModelCreating() method is not called in model-first and thus I have no DbModelBuilder instance.
The only thing I can think of is executing some kind of manual SQL statement at application start that creates the UNIQUE constraint, which kind of defeats the purpose of EF.
Here is my current DbContext class:
public partial class UserAccountsModelContainer : DbContext
{
public UserAccountsModelContainer()
: base("name=UserAccountsModelContainer")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<UserAccount> UserAccounts { get; set; }
}
I won't even bother to post the UserAccount class since it's auto-generated and shouldn't be modified (I know that the DbContext is also auto-generated, but modifying it is possible).
Any help on this is appreciated!
First I will recommend you to switch to Entity Framework Code First, too. It gives you much more controll about every thing that is possible with EF.
I never used it before, but I know Model Conventions. They are applicable to the model configuration. Maybe it will be an approach to set up a convention for a defined model type/property that should be configured as unique constraint.
Based on the following it should be possible to modify the set up of model first on creating database.
Model Conventions are based on the underlying model metadata. There
are conventions for both CSDL and SSDL. Create a class that implements
IConceptualModelConvention from CSDL conventions and implement
IStoreModelConvention for SSDL convention.
Source: http://www.entityframeworktutorial.net/entityframework6/custom-conventions-codefirst.aspx
There are two types of model conventions, Conceptual (C-Space) and
Store (S-Space). This distinction indicates where in the pipeline a
convention is executed. A C-Space convention is applied to the model
that the application builds, whereas an S-Space convention is applied
to the version of the model.
Source: https://entityframework.codeplex.com/wikipage?title=Custom%20Conventions
Some more example implementations incl. explainations are findabe on msdn. I guess they are very helpful for your case.
One example from MSDN:
public class DiscriminatorRenamingConvention : IStoreModelConvention<EdmProperty>
{
public void Apply(EdmProperty property, DbModel model)
{
if (property.Name == "Discriminator")
{
property.Name = "EntityType";
}
}
}
It will rename the column Discriminator into EntityType. It is a very simple example but you could modify it to solve your problem to:
public class ModelBasedConvention : IConceptualModelConvention<EdmProperty>
{
public void Apply(EdmProperty property, DbModel model)
{
if (property.Name == "Username"
&& property.DeclaringType.GetType() == typeof(UserAccount))
{
property.AddAnnotation("UniqueKey", property);
}
}
}

Entity Framework - Existing Database, classes in seperate library

I'm looking for information about using entity framework with an existing database, but to keep my poco classes in another library.
I've done this a number of times in the past, but I've always ended up with my model classes in my data access library using EF and my domain classes in a separate library. Inevitably this meant writing code to translate between my domain classes and my model classes. This seems pointless and inefficient since the classes are usually almost identical.
Can anyone point me to a walkthrough keeping my classes are materialized by EF in a separate library? I would need to be able to do some minor name correction (eg Filter_Rule --> FilterRule). I would also like to be able to keep anything EF specific in the data access library so that I can swap out the data access library if I need to.
Thanks,
Jason
This should be quite straightforward. Create a DbContext code-first style as normal, adding DbSets and configurations as necessary to tell EF about your database. Set your initializer to null so it doesn't try to mess with your existing database, and voila...
public class YourContext : DbContext
{
public DbSet<YourPoco> YourPocos { get; set; }
static YourContext()
{
Database.SetInitializer<YourContext>(null);
}
public YourContext() : base("database_name")
{
}
protected override void OnModelCreating(DbModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<YourPoco>().Property(x => x.FilterRule).HasColumnName("Filter_Rule");
//OR
builder.Configurations.Add(new YourPocoConfig());
//OR
builder.Configurations.AddFromAssembly(typeof (YourContext).Assembly);
}
}
public class YourPocoConfig : EntityTypeConfiguration<YourPoco>
{
public YourPocoConfig()
{
HasKey(x => x.Id);
Property(x => x.FilterRule).HasColumnName("Filter_Rule");
}
}
If you are worried about getting everything to match your database structure, you can use Entity Framework Tools for Visual Studio to reverse engineer your models, then match the configuraiton or copy the generated POCO's into your other library and convert the data annotations into respective EntityTypeConfiguration classes to keep the POCO's clean.
MSDN document on reverse engineering code-first.

Breezejs and type inheritance: a few questions

I use breeze with Entity Framework 6 Code First, C# Web Api 2 and Knockout.
Everything was rather fine until I added descendant type for one of my entity types. This resulted in broking behaviour on several parts of my app. The cause of problems:
now entityManager.getEntityByKey('baseTypeName', id, true) always returns entity of descendant type
extending base type with baseEntityType.dataProperties.push(prop) does not affect entities of descendant type
I decided to remove descendant type from metadata:
public class DbContextForBreezeMetadata : MyDbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Ignore<DescendantType>();
base.OnModelCreating(modelBuilder);
}
}
public class EntityContextProvider : EFContextProvider<MyDbContext>
{
protected override string BuildJsonMetadata()
{
return new EFContextProvider<DbContextForBreezeMetadata>().Metadata();
}
}
After doing that I saw that all properties of base entities became dependentObservables.
So, the questions: is it a way to get breeze to work with such entities as if they are of not related types? How to change metadata (removing descendant type) so that base entities would have observables but not dependentObservables as properties?
Take a look at the DocCode sample in the breeze.js.samples repo. The are several examples of inheritance models there using EF.

How can NodaTime be used with EF Code First?

I really want to be able to use NodaTime in my Entity Framework Code First database projects but haven't found a "clean" way to do it. What I really want to do is this:
public class Photoshoot
{
public Guid PhotoshootId{get; set;}
public LocalDate ShootDate{get; set;} //ef ignores this property
}
Is there any supported or recommended approach to using NodaTime with EF Code First?
Until custom primitive type persistence is natively supported in Entity Framework, a common work around is to use buddy properties.
For each custom primitive within your domain model, you create an associated mapped primitive to hold the value in a format supported by Entity Framework. The custom primitive properties are then calculated from the value of their corresponding buddy property.
For example:
public class Photoshoot
{
// mapped
public Guid PhotoshootId{get; set;}
// mapped buddy property to ShootDate
public DateTime ShootDateValue { get; set; }
// non-mapped domain properties
public LocalDate ShootDate
{
get { // calculate from buddy property }
set { // set the buddy property }
}
}
We use NodaTime in our code first POCO's using exactly this approach.
Obviously this leaves you with a single type acting as both a code first POCO and a domain type. This can be improved at the expense of complexity by separating out the different responsibilities into two types and mapping between them. A half-way alternative is to push the domain properties into a subtype and make all mapped buddy properties protected. With a certain amount of wanging Entity Framework can be made to map to protected properties.
This rather splendid blog post evaluates Entity Framework support for various domain modelling constructs including encapsulated primitives. This is where I initially found the concept of buddy properties when setting up our POCO's:
http://lostechies.com/jimmybogard/2014/04/29/domain-modeling-with-entity-framework-scorecard/
A further blog post in that series discusses mapping to protected properties: http://lostechies.com/jimmybogard/2014/05/09/missing-ef-feature-workarounds-encapsulated-collections/
EF Core 2.1 has a new feature Value Conversions, which is exactly for this scenario.
//OnModelCreating
builder.Entity<MyEntity>
.Property(e => e.SomeInstant)
.HasConversion(v => v.ToDateTimeOffset(), v => Instant.FromDateTimeOffset(v));
.HasConversion has some other overloads to make this logic re-useable, for example you can define your own ValueConverter.
No "clean" way that I'm aware of because EF, as of this writing, doesn't have a mechanism for simple type conversion like you see in NHibernate (IUserType). A real limitation in EF as an ORM which causes me to change my domain to suit my ORM.
There is a provider specific way that works with Postgres (Npgsql).
Install the library
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL.NodaTime
And then while configuring DbContext, use this,
services.AddDbContext<PhotoshootDbContext>(opt =>opt.UseNpgsql(Configuration.GetConnectionString("ConnectionString"), o => o.UseNodaTime()));
There are some third party libraries for other providers too.

Using Entity Framework in a modular application

I'm currently working on an MVC-project that should be highly modular. For example I want to have a user-module, a menu-module and a page module.
Because the modules need to be highly re-usable in different visual studio solutions I create separate projects for each module.
For the database mapping I would like to make use of the entity framework. I've created a separate DbContext in each module-project. Each DbContext contains the entities associated with the module.
Unfortunately I'm not able to let EF create foreign keys between entities in different modules/dbContexts.
For example:
Core module contains User-Entity
Page module contains Page-Entity which has an author that links to the User-entity defined in the core-module dbContext.
Has anyone an idea how I can create foreign keys across modules/dbContexts?
Are all of your entities in the same database? I would suggest separating your assemblies like this:
Data - project containing your Entity Framework model and/or class/entity definitions (depending on which type of EF approach you are using).
Service - project containing interfaces and classes that manipulate your data. Example, for your User entity (and related items), you might have this:
public interface IUser : IDisposable
{
Data.User Get(int userId);
IQueryable<Data.User> GetAll();
//other method definitions for User entity CRUD
}
Then, you implementation:
public class User : IUser
{
private readonly DataEntities _dataContext = new DataEntities(); //this is from your EF Data assembly
public Data.User Get(int userId)
{
return _dataContext.Users.FirstOrDefault(u => u.UserId == userId);
}
public IQueryable<Data.User> GetAll()
{
return _dataContext.Users;
}
//other method implementations
public void Dispose()
{
_dataContext.Dispose();
}
}
Then, reference both your Service and Data assemblies in your module projects.