Using Entity Framework in a modular application - entity-framework

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.

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.

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

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).

Entity Framework 5.0 Repository with dynamic DbContext

As it says on the tin, is it possible to create an instance of a DbContext suitable for use as an Entity Framework 5.0 POCO context where the properies that are normally declared as
public DbSet<T> Entities { get; set; }
aren't set/known until runtime?
I'd like to make a repository that has methods like
public TEntity Find<TEntity>(object key) where TEntity : class
{
return _context.Set<TEntity>().Find(key);
}
public void Update<TEntity>(TEntity entity) where TEntity : class
{
if (_context.Entry(entity).State == EntityState.Detached) //entity is detached
_context.Set<TEntity>().Attach(entity);
_context.Entry(entity).State = EntityState.Modified;
}
.... etc
And then use them like:
Widget w = repository.Find<Widget>(123);
repository.SaveChanges();
This is trivial if the repository's context is set to a class that contains a DbSet<Widget> Widgets, but can it be done such that the entity types that I plan to use won't be know until runtime OR possibly not until I actually USE them? So that if I have a new class Foo, I can immediately query my repository to .Find<Foo>(123) without having to first add a DbSet<Foo> Foos to my DbContext class?
I think this should be possible because there's nothing special about the poco classes or the DbContext instance which holds references to them.
You don't need DbSet<Foo> Foos property in your context. That is just one way to tell context about existence of the Foo entity. There are multiple ways how context discovers mapped entities:
By explicit DbSet<T> properties
By navigation properties in already discovered entities
By specifying mapping in DbModelBuilder
Overriding OnModelCreated in your context type
Creating DbModelBuilder manually, building it and compiling it into DbCompiledModel which can be passed to DbContext constructor
By declaring EntityTypeConfiguration<T> for each entity and adding it to DbModelBuilder (either in OnModelCreated or in manually created DbModelBuilder).
The last option can be used to discover all required entities at application startup (for example by searching assemblies for all entity configuration classes and registering them to model builder) but it is still not fully dynamic solution. Compiled model is normally constructed only once per application run when the context is used for the first time. Without replacing the compiled model you cannot add or remove mapped entity types to the context.

EntityFramwork generating Interfaces for MEF

I am playing around building some buildingblocks based on database tables.
So I've created an UsersManager and a ValidationManager both based on the EDMX "templates".
I'd really like to loose couple those two components with MEF. But therefore i need to create Interfaces of the entityobjects exposed in the ValidationManager.
Is there an easy way of creating those Interfaces, in that manner i can still use the EDMX generated classes?
Thanx,
Paul
Using an example of a database with a Product Table, is this what you're trying to achieve....
but still use generated entity classes (using either the standard EF generator or another POCO generator of some sort).
I'm not sure - as you mention MEF and I don't see it being directly related.
The generated entity classes are partial classes which will allow you to extend the generated class which in this case you want to extend to implement an interface.
Presuming the following interface is going to be used to introduce the layer of abstraction...
public interface IEntity {
public bool IsDeleted { get; set; }
}
Create a new class file with and extended Product class...
public partial class Product : IEntity {
public bool IsDeleted {
get {
throw new NotImplementedException();
}
set {
throw new NotImplementedException();
}
}
}
You have now extended your generated entity Product with the partial class custom code - and you can use it as normal through EF.
Now instead of your UserManager and ValidationManager classes having a hard reference to Product, instead they'll only have reference to IEntity.
If I didn't understand the question, please provide more details on exactly it is you want to do.