I am programming a few projects which have some core functionality which are similar and then their own functionality outside of that.
I was considering making a class library, using Entity Framework with Code First in order to provide some shared functionality and the database tables that go with it.
For example, I may want to use the class library to send an email and then use entity framework to log in a database table that an email is sent.
This class library would be added into another project, which also uses entity framework - in the same database. So now I would like the database to "build itself", creating the email logging table and some other functionality, e.g. products of some sort.
I have not used Entity Framework before, will having two dlls end up causing any kind of confusion because they're both pointing to the same database but expect different tables? e.g. would they be inclined to delete tables because they don't appear in the code?
Will it also cause problems if I end up over-lapping, e.g. if I want to do a join on all products (Project Entity Framework) which have had an email (Class Library Entity Framework) sent out, would I be able to do a join via linq?
You'll want to keep everything in one DbContext. You can do this by using interfaces to group the entities in each dll, then declare a concrete DbContext class that combines them all in your top-level code.
Project1:
public interface IMyProj1DbContext : IDbContext
{
DbSet<Person> People { get; set; }
DbSet<Place> Places { get; set; }
}
Project2:
public interface IMyProj2DbContext : IDbContext
{
DbSet<Customer> Customers { get; set; }
DbSet<Order> Orders { get; set; }
}
And you'll need a third project that defines the common members:
public interface IDbContext
{
int SaveChanges();
}
Now in the code where all these come together, you can declare a single DbContext class that inmplements all of the interfaces:
public class MyDbContext : DbContext, IMyProj1DbContext, IMyProj2DbContext
{
public DbSet<Person> People { get; set; }
public DbSet<Place> Places { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<Order> Orders { get; set; }
}
Now, you will want to write the code that uses the two different contexts and that code will live inside the individual dlls for each context. But how can you do that?
public class PersonFinder
{
public Person FindPersonByLocation(Place placeToSearch)
{
using (var db = new ???)
{
return db.People.SingleOrDefault(p => p.Location_Id == placeToSearch.Id);
}
}
}
You can't reference the concrete DbContext here because that will cause a circular dependency. The key is to inject the DbContext object at run-time:
public class PersonFinder : Disposable
{
IMyProj1DbContext _db;
public PersonFinder(IMyProj1DbContext db)
{
_db = db;
}
public Person FindPersonByLocation(Place placeToSearch)
{
return _db.People.SingleOrDefault(p => p.Location_Id == placeToSearch.Id);
}
public void Dispose()
{
// ... Proper dispose pattern implementation excluded for brevity
if (_db != null && _db is Disposable)
((Disposable)_db).Dispose();
}
}
*This is not the best way to inject a disposable object, by the way. But it is relatively safe to do it this way and it demonstrates the principle without the extra clutter.
Now you only have one DbContext and EF will generate and maintain one single database, even though you have nice logical domain silos that can operate independently.
When you want to perform a join between the silo entities you code can use the MyDbContext class directly.
Related
The main problem is that when the web app is launched to the internet, when the load is high an exception is raised telling that there is already an opened data reader.
The following are the specs we use:
Entityframework 5.0.0
MySQL database
Is there a way of solving this problem without the using(){} block? Main problem of this approach is that when closed the using block I can't expand foreign key relations of entityframework objects inside the html view.
I also attach some source code, showing how we keep a single database context through the whole application
public abstract class AbstractService
{
public Entities db_model
{
get
{
return DbContext.Instance.db_model;
}
}
}
public class DbContext
{
public Entities db_model = new Entities();
private static DbContext _dbContext;
public static DbContext Instance
{
get
{
if(_dbContext == null)
{
_dbContext = new DbContext();
}
return _dbContext;
}
}
}
This answer is specifically related to the issue mentioned in the question about using the loaded entities in an ASP.NET View. The question asks about a way of solving this problem without a using block or disposing of the DbContext, however I am suggesting doing exactly this.
The reason being that it's generally desirable not to use Entity Framework objects in the ASP.NET Views because those objects are a lot more more than just plain POCO objects; they hide logic which allows them to act as a proxy to the underlying database, so they have a hidden dependency on the state of the DbContext which created them.
Here's a contrived example using EF models for Employee and Department with a DbContext:
public class CompanyDbContext : DbContext
{
public DbSet<Department> Departments { get; set; }
public DbSet<Employee> Employees { get; set; }
}
public class Department
{
public long Id { get; set; }
public virtual ICollection<Employee> Employees { get; set; }
}
public class Employee
{
public long Id { get; set; }
public long DepartmentId { get; set; }
public virtual Department Department { get; set; }
}
If these were used in an ASP.NET application, I would create some separate models which aren't tied to Entity Framework, to be used by ASP.NET. For example:
public class DepartmentModel
{
public long Id { get; set; }
public List<EmployeeModel> Employees { get; set; }
}
public class EmployeeModel
{
public long Id { get; set; }
public long DepartmentId { get; set; }
}
A few considerations:
According to the MSDN docs, "A DbContext represents a combination of the UnitOfWork and Repository patterns" - https://learn.microsoft.com/en-us/dotnet/api/system.data.entity.dbcontext?redirectedfrom=MSDN&view=entity-framework-6.2.0 - Therefore the DbContext should be short lived as far as possible.
When loading data from the context, related entities can be retrieved using DbSet<>.Include() - https://learn.microsoft.com/en-us/ef/ef6/querying/related-data
Generally speaking, it makes sense to de-couple the 'data' layer from the 'view' layer - for all kinds of reasons, some of which are listed here: https://learn.microsoft.com/en-us/aspnet/web-api/overview/data/using-web-api-with-entity-framework/part-5 -- this involves mapping between the EF objects and the POCO Models.
The logic which is used to query the DbContext would query the data using EF, and return that data using POCO models so that only logic which deals directly with DbContext has any involvement with the EF objects. For example:
public List<DepartmentModel> GetAllDepartments()
{
using (var ctx = new CompanyDbContext())
{
// Ensure that related data is loaded
var departments = ctx.Departments
.Include(d => d.Employees);
// Manual mapping by converting into a new set of models to be used by the Views
var models = departments
.Select(d => new DepartmentModel
{
Id = d.Id,
Employees = d.Employees
.Select(e => new EmployeeModel
{
Id = e.Id,
DepartmentId = e.DepartmentId
})
.ToList(),
})
.ToList();
return models;
}
}
Being able to use those POCO models, while requiring some extra boilerplate code, provides complete separation between the DbContext and ASP.NET, allowing the data to be used without ASP.NET Views/Controllers being concerned by the lifetime or state of the DbContext.
Sometimes this may look as if this approach violates the 'DRY' principle, however I would point out that EF objects and ViewModel objects exist to solve different problems, and it's not uncommon for the ViewModel objects to take a different shape, or even to require additional fields/attributes which wouldn't be suitable to add to the EF classes.
Lastly, the above uses 'manual' mapping, but if the mappings are really simple and straightforward, then it could make more sense to use AutoMapper instead: Cleanest Way To Map Entity To DTO With Linq Select?
My project is layered as follows:-
DAL (Entity) --> BLL (DTO) --> ApplicationComponent (ViewModel).
There will be multiple components of application (ApplicationComponent) which will access BLL. Components include windows services, web services, web API and MVC controller.
I am transforming NHibernate Entity objects to DTO objects while passing them from DAL to BLL. While passing this state to ApplicationComponent, BLL again converts it to ViewModel.
This helps me separate the concerns and how data is handled in each layer. I am not in favor of returning NHibernate Entity object to view for following reasons: -
Data get exposed to UI that I want to hide (or only expose if needed) like passwords, user type, permission etc.
On references/joins, NHibernate executes additional queries when property is accessed which nullify the use of lazy loading.
Unnecessary data exposed to user (of Entity) creates confusion and gap for bugs.
Persistence implementations leaking into BLL/UI. Entity is not designed for UI. It cannot serve UI in all cases.
We use attributes on DTO properties for user input validation which looks odd with Entity.
I am facing following problems with this approach: -
Biggest and obvious problem is redundant objects with similar members and functionality.
I have to write mapper methods in each layer to transform object. This could be minimized by using AutoMapper or something similar; but it does not fully resolve problem.
Questions:-
Is this an over separation and should be avoided (at least minimized)?
If this approach is correct, I do not see any simple way to fully bypass two problems I stated above. Please suggest.
If this approach is incorrect, please suggest corrections.
References:-
Link1 suggests to transfer Entity object to view which in my understanding not a good idea.
Link2 suggests to map Entity with DTO that I am already doing.
Link3 does not help.
Link4 suggests using something like auto mapper tools which is OK. But it still does not solve the problem completely.
Link5 is great post. It explains why those should be separate which I agree. It does not comment on how to minimize the overhead caused by it.
Link6 is not helpful again.
Link7 is an excellent answer which suggests use Entity as is in UI if possible. It still does not apply to most of my project.
Linl8 is another excellent resource that suggest to go on mapping two way as I am doing now. It still does not suggest a way to minimize overhead.
Have you considered creating a shared interface between the DTO and the Entity? You should not tightly couple your ORM to the rest of your application. Or in fact use anything other than interfaces between them if at all possible.
You could, in theory, have a separate project that just holds the contract/abstractions of what you expect to be passed around. To minimize mapping overhead and to leave it open for the extension you can ensure that the entity implements the interface as expected (omitting what is not needed), and in cases where you need a bespoke DTO you can create a model with mapping using the interfaces.
There is some overhead when adding extra interface projects but it will keep your code cleaner and more maintainable in the long run.
namespace Data
{
public class FakeRepo : IFakeRepo
{
public IThisIsAnEntity GetEntity()
{
return new ThisIsAnEntity();
}
}
public class ThisIsAnEntity : IThisIsAnEntity
{
public string HiddenField { get; set; }
public long Id { get; set; }
public string SomeField { get; set; }
public string AnotherField { get; set; }
}
}
namespace Data.Abstractions
{
public interface IFakeRepo
{
IThisIsAnEntity GetEntity();
}
}
namespace Abstractions
{
public interface IThisIsAnEntity : IThisIsAnSlimmedDownEntity
{
string SomeField { get; set; }
}
public interface IThisIsAnSlimmedDownEntity
{
long Id { get; set; }
string AnotherField { get; set; }
}
}
namespace Services.Abstractions
{
public interface ISomeBusinessLogic
{
IThisIsAnEntity GetEntity();
IThisIsAnSlimmedDownEntity GetSlimmedDownEntity();
}
}
namespace Services
{
public class SomeBusinessLogic : ISomeBusinessLogic
{
private readonly IFakeRepo _repo;
public SomeBusinessLogic(IFakeRepo repo)
{
_repo = repo;
}
public IThisIsAnEntity GetEntity()
{
return _repo.GetEntity();
}
public IThisIsAnSlimmedDownEntity GetSlimmedDownEntity()
{
return _repo.GetEntity();
}
}
}
namespace UI
{
public class SomeUi
{
private readonly ISomeBusinessLogic _service;
public SomeUi(ISomeBusinessLogic service)
{
_service = service;
}
public IThisIsAnSlimmedDownEntity GetViewModel()
{
return _service.GetSlimmedDownEntity();
}
public IComposite GetCompositeViewModel()
{
var dto = _service.GetSlimmedDownEntity();
var viewModel = Mapper.Map<IThisIsAnSlimmedDownEntity, IComposite>(dto);
viewModel.SomethingSpecial = "Something else";
return viewModel;
}
}
public class SomeViewModel : IComposite
{
public long Id { get; set; }
public string AnotherField { get; set; }
public string SomethingSpecial { get; set; }
}
}
namespace UI.Abstractions
{
public interface IComposite : IThisIsAnSlimmedDownEntity, ISomeExtraInfo
{
}
public interface ISomeExtraInfo
{
string SomethingSpecial { get; set; }
}
}
nhibernate is one of those orm`s that allow you to avoid having DAL entities and it will be better for performance to avoid extra mapping from BLL TO DAL, but if it is not critical for you, it will be better to keep it at as it is to have application layers loose coupled
I'm prototyping an ASP.NET Web API that needs to talk to several databases which are almost identical. Each of our customers have their own instance of our database structure, but some are specialized to integrate with other systems they have. So for example in one database the Client table might have the column AbcID to reference a table in another system, but other databases won't have this column. Other than that the two tables are identical in name and columns. The columns can also have different lengths, varchar(50) instead of varchar(40) for example. And in some databases there can be one extra table. I have focused on solving the different columns problem first.
I was hoping to use an ORM to handle the data access layer of the API, and right now I'm experimenting with Entity framework. I already solved how to dynamically connect to the different databases from an API-call, but right now they have to be completely identical in structure.
I have tried to set up double .edmx models with a Database-first approach but this causes conflicting class names between the models. So instead I tried Code-first and come up with this (which isn't working).
DbContext extension:
In the constructor I check which database is being accessed and if it is one of the special ones I flag it for the model configuration.
public partial class MK_DatabaseEntities : DbContext
{
private string _dbType = "dbTypeDefault";
public DbSet<Client> Client { get; set; }
public DbSet<Resource> Resource { get; set; }
public MK_DatabaseEntities(string _companycode)
: base(GetConnectionString(_companycode))
{
if(_companycode == "Foo")
this._dbType = "dbType1";
}
// Add model configurations
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Configurations
.Add(new ClientConfiguration(_dbType))
.Add(new ResourceConfiguration());
}
public static string GetConnectionString(string _companycode)
{
string _dbName = "MK_" + _companycode;
// Start out by creating the SQL Server connection string
SqlConnectionStringBuilder sqlBuilder = new SqlConnectionStringBuilder();
sqlBuilder.DataSource = Properties.Settings.Default.ServerName;
sqlBuilder.UserID = Properties.Settings.Default.ServerUserName;
sqlBuilder.Password = Properties.Settings.Default.ServerPassword;
// The name of the database on the server
sqlBuilder.InitialCatalog = _dbName;
sqlBuilder.IntegratedSecurity = false;
sqlBuilder.ApplicationName = "EntityFramework";
sqlBuilder.MultipleActiveResultSets = true;
string sbstr = sqlBuilder.ToString();
return sbstr;
}
}
ClientConfiguration:
In the configuration for Client I check the flag before mapping properties to database columns. This however does not seem to work.
public class ClientConfiguration : EntityTypeConfiguration<Client>
{
public ClientConfiguration(string _dbType)
{
HasKey(k => k.Id);
Property(p => p.Id)
.HasColumnName("ID")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
if (_dbType == "dbType1")
{
Property(p => p.AbcId).HasColumnName("AbcID");
}
Property(p => p.FirstName).HasColumnName("FirstName");
Property(p => p.LastName).HasColumnName("LastName");
}
}
Client class:
This is how my Client class looks like, nothing weird here.
public class Client : IIdentifiable
{
public int Id { get; set; }
public string AbcId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public interface IIdentifiable
{
int Id { get; }
}
Back-up solution is to use raw SQL queries to deal with the offending tables and ORM for the rest, but it would be awesome if there is some way to do this that I have not thought of. Right now I'm trying Entity framework, but I am not opposed to trying some other ORM if that one can do it better.
Using Code First supports this scenario:
1) Common entities for both models:
public class Table1
{
public int Id { get; set; }
public string Name { get; set; }
}
2) Base version of table 2
public class Table2A
{
public int Id { get; set; }
public int Name2 { get; set; }
public Table1 Table1 { get; set; }
}
3) "Extended" version of table 2, inherits version A, and adds an extra column
public class Table2B : Table2A
{
public int Fk { get; set; }
}
4) Base context, including only the common entities. Note that there is a constructor which accepts a connection string, so there is no parameterless constructor. This forces inheriting contexts to provide their particular connection string.
public class CommonDbContext : DbContext
{
public CommonDbContext(string connectionString)
:base(connectionString)
{
}
public IDbSet<Table1> Tables1 { get; set; }
}
5) The context A, inherits the common context, adds the Table2A, and ignores the Table2B
public class DbContextA : CommonDbContext
{
public DbContextA() : base("SimilarA") { } // connection for A
public IDbSet<Table2A> Tables2A { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Ignore<Table2B>(); // Ignore Table B
}
}
The context B, inherits the common, and includes the Table2B
public class DbContextB: CommonDbContext
{
public DbContextB() :base("SimilarB") { } // Connection for B
public IDbSet Tables2B { get; set; }
}
With this setup, you can instance either DbContextA or DbContextB. One advantage is that both inherit CommonDbContext, so you can use a variable of this base class to access the common entities, no matter if the concrete implementation is version A or B. You only need to change to the concrete type to access the specific entities of A or B (Table2A or Table2Bin this sample).
You can use a factory, or DI or whatever to get the required context depending on the DB. For example this could be your factory implementation:
public class CommonDbContextFactory
{
public static CommonDbContext GetDbContext(string contextVersion)
{
switch (contextVersion)
{
case "A":
return new DbContextA();
case "B":
return new DbContextB();
default:
throw new ArgumentException("Missing DbContext", "contextVersion");
}
}
}
NOTE: this is working sample code. You can of course adapt it to your particular case. I wanted to keep it simple to show how it works. For your case you'll probably need to change the factory implementation, and expose the connection string in A and B context constructors, and provide it in the factory method
Handling the different classes of your entities
The easiest way to handle the different entities of each DbContext is to use polymorphism, and or generics.
If you use polymorphism you need to implement methods which use the type of the base class (as parameter and as return type). This parameters and vars will hold entities either of the base or of the derived class (Table2A or Table2B). In this case, each context will receive an entity of the right type, and it will work directly without trouble.
The problem is when your app is multilayered, uses services or is a web app. In this case when you use the base class the polymorphic behavior can be lost, and you'll need to handle the entities of the base class. (For example if you let the user edit an entity of derived class in a web app form, the form can only take care of the properties of the base class, and when it's posted back, the properties of the derived class will be lost) In this case, you need to handle it intelligently (see note below):
For reading purposes, if you have a Table2B, you have a direct casting to Table2A. You can implement functionality for Table2A and directly used it. I.e. you can return collections or individual values of the base class (in many cases implicit casting will be enough). No more worries.
For inserting/updating, you have to take extra steps, but it's not too difficult. You need to implement methods that receive/return Table2A parameters in your contexts, or in another layer, depending on your architecture. For example, you can make the base context abstract and define virtual methods for this. (See example below). Then you need to make the right implementation for each particular case.
if you receive a Table2A but need to insert it in Table2B, simply map entity A into entity B with AutoMapper or ValueInjecter and fill the remaining properties with default values (beware of AutoMapper and EF dynamic proxies: it won't work).
if you receive a Table2A and need to update a Table2B, simply read the existing entity from the DB and repeat the mapping procedure (ValueInjecter will be less troublesome than AutoMapper also for this case).
This is a very simple example of what can be done, but you need to adapt it to your particular case:
Inside CommonDbContext class, declare virtual methods for the base type, like this:
public virtual Table2A GetTable2AById(int id);
public virtual void InsertTable2A(Table2A table);
You can also use generic interfaces/ methods, instead of abstract class / virtual methods, like this:
public T GetTable2AById<T>(int id)
{
// The implementation
}
In this case you should add the necessary constraints to the T type, like where T: Table2A or the ones you need (class new()).
NOTE It's not exact to say that the polymorphism is lost in this cases, because you can really make polymorphic Web Services with WCF, or Web API, adapt your UI to the real class of your entity (with templates for each case) and so on. That depends on what you need or want to achieve.
Been there, done that.
In all seriousness: dump EF in this specific case; it will bring a lot of pain and suffering for no benefit.
What you'll eventually end up doing (putting my Fortuneteller Hat on) is you'll rip out all the EF-based code, create an abstract object model and then write a series of backends that will map all the various database structures back and forth to said clean abstract object model. And you'll be either using raw SQL or something lightweight like Dapper or BLToolkit.
When I program using LINQ with a .dbml file, there is only one context. But, when I do an MVC site, it seems like I have separate contexts for each entity (which is the way the MVC tutorial showed me how to do it; with "movies" context).
I have:
public class AccountsContext : DbContext
{
public AccountsContext()
: base("DefaultConnection")
{
}
public DbSet<Account> Accounts { get; set; }
}
And, I have:
public class ClientsContext : DbContext
{
public ClientsContext()
: base("DefaultConnection")
{
}
public DbSet<Client> Clients { get; set; }
}
When I call these, I have to create separate contexts, like:
private AccountsContext db = new AccountsContext();
private ClientsContext clientsContext = new ClientsContext();
... Which is both annoying, and it seems redundant since I know that when I use LINQ, I only have to instantiate a single database object.
Is there a way to use only one contextŠ± and is this recommended?
There shouldn't be anything stopping you from using one context. The database, and the tooling used to access it, should be completely independent of anything outside of it (business logic, service layer, UI, etc...).
The number of contexts, or how you use them, shouldn't change based on your client technology.
What about MVC leads you to believe that you would need more than one context? And what's stopping you from doing so?
If you think you need to use a context for each entity, because the sample was that way, you don't. Just use one context.
If it helps, this is what a simple context looks like with more than one entity:
public partial class abook_dbEntities : DbContext
{
public abook_dbEntities()
: base("name=abook_dbEntities")
{
}
public DbSet<Entity> Entities { get; set; }
public DbSet<Contact> Contacts { get; set; }
}
If it helps, a typical business flow looks like this:
UI -> Controller -> Business logic -> Data access -> Database
Your data contexts would go in your data layer. Your logic would go in your business logic layer.
Im creating a class library that will be used in several projects. This library includes a handfull of entities with associated tables in the database. My question is: how do I create these tables when I include this library in a project?
I suspect you want a library of objects that are used to generate a database?
If so you can achieve this with EntityFramework CodeFirst.
At minimum you'll need your objects and a DbContext.
a typical set up maybe as follows:
Entities
public class Person {
public string FirstName { get; set; }
public string LastName { get; set; }
}
DbContext
public class MyDbContext : System.Data.Entity.DbContext {
public MyDbContext(string nameOrConnectionString) : base(nameOrConnectionString)
public DbSet<Person> People { get; set; }
}
These would live in your project and when you add a reference to it, for example a web project. There are different ways to build the Database, you could call the constructor (MyDbContext) from your web project and pass a connection string to a server.