Recently, I've got request to make my DbContext model mockable.
However, currently it is defined like this:
public MyDbContext : DbContext
{
public DbSet<Employee> Employees {get;set;}
}
I was thinking to abstract it to:
public interface IMyDbContext
{
IDbSet<Employee> Employees {get;set;}
}
public MyDbContext : DbContext, IMyDbContext
{
IDbSet<Employee> Employees {get;set;}
}
Do I lose anything if I swap DbSet with IDbSet in my MyDbContext implementation?
I think the mock and real database object should share the same interface. That way you can swap out your database implementation without affecting clients. Mocking is easier, too. Aspect oriented programming is easier. I can't think of a good reason not to start both with an interface.
Related
I am new to the ASP.NET WebAPI project and building the new project with the following structure :-
Project.MainAPIService
Project.BusinessManager
Project.Model
Project.Repository
Project.Common
I am using Autofac to perform the DI in the whole project. And the flow is like this :-
API controller >>>>>> (DI) Business Manager >>>> (DI) Repository & creates the DBContext object manually.
My Repository class is looking like this. And now i want to pass the client-name dynamically into the Repository class, so that it makes the DB connection to the particular client db only. But i unable to pass the client-name from businessManager project to PDLRepository and further down to DBContext class.
public class MyRepository : IMyRepository, IDisposable
{
myContext _context = new myContext("ClientX");
private IGenericRepository<Mapping> _docMappingGenericRepo;
private IGenericRepository<Document> _DocGenericRepo;
private IGenericRepository<Activity> _activityGenericRepo;
}
mycontext class looks like this :-
public partial class mycontext : DbContext
{
public mycontext (string ClientName)
: base(ConnectionUtil.GetConnectionString(ClientName))
{ }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<myContext>(null);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
public virtual DbSet<DocumentMapping> DocumentMapping { get; set; }
public virtual DbSet<Document> Document { get; set; }
}
Please suggest your views how to fix the myContext or MyRepository class accordingly. How will i pass the client-name from BusinessManager to Repository to DBContext class ?
Please help me out here.
Do not create myContext in Repository. Remove following line from Repository.
myContext _context = new myContext("ClientX");
Instead, create and manage myContext in BusinessManager. As BusinessManager already know ClientName, it can be created there without trouble with the same line we removed from Repository.
Now, inject myContext in Repository.
You apparently have multiple databases; one per client. So one database represent one client. Connection represents Database and myContext is handling Connection. So, approach I mentioned above makes more sense.
Repository executes the action, it should not control Connection. Using this approach, you can also include multiple Repositories in one myContext which will help you cover all those repositories under one transaction/UoW.
This answer explains how to do this with Dapper. Technology may not be related to you; but rest of the details may help you.
I'm starting to use EFCore in a UWP app with SQLite. I've declared the classes that I want stored in the database. I've then declared various DbSets and the OnConfiguring override:
public class DatabaseContext : DbContext
{
public DbSet<Person> People { get; set; }
public DbSet<Relationship> Relationships { get; set; }
public DbSet<SourceDescription> SourceDescriptions { get; set; }
public DbSet<Agent> Agents { get; set; }
public DbSet<Event> Events { get; set; }
public DbSet<Document> Documents { get; set; }
public DbSet<PlaceDescription> PlaceDescriptions { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Filename=Testing.db");
}
}
In the Package Manager Console, I then go:
Add-Migration 2017-06-23
and it creates the code to then build the database. HOWEVER, that code is missing some of the top-level tables. Some of them are there but some aren't and I can't see/figure out what is causing this. No errors are generated and I cannot find a pattern to determine why the missing tables are missing.
Further information:
There are 29 classes defined in my code. The migration code creates 24 tables.
Of the 5 "missing" classes, 4 of them are derived from Subject which, in turn, derives from Conclusion. The fifth is the Conclusion class. Since the migration code "merges" the properties from each of the derived classes, I'm not surprised that the Conclusion class doesn't have its own table as there is no direct use of it as a class.
With the exception of the Conclusion class, the other 4 classes are only referenced in the DbSet properties (as opposed to be used in properties in other classes). As noted above, the Document class is derived from another class, so it isn't derived classes that is the common factor.
It isn't that some of the classes are partial classes.
I can't spot anything about the properties in the classes that is a common factor. For example, the Person class has List a couple of times but so does the Agent class and that does appear in the migration code.
Any suggestions on what I can look for or if this is a known issue?
To clarify, the answer provided by Ivan is that EF Core sees the four classes that are derived from the Subject class and builds a table for the Subject class that includes all of the properties for those derived classes. There is then a Discriminator column added to the Subject class that indicates which derived class this is for.
http://www.learnentityframeworkcore.com/inheritance/table-per-hierarchy is a good article for explaining it.
An interesting approach to designing database tables that I hadn't come across before. I live and learn :)
In my app i have two DataContexts, ApplicationDbContext created by default ,which inherits from IdentityDbContext and DomainContext for my model. Now i am getting some issues when updating the database using Migrations, when i execute
Add-Migration to DomainContext in the migration file created is included the code to Drop all the tables related to ApplicationDbContext. I have googled and i have not found any satisfactory answer yet, the only rasonable solution suggest to mingle both DBContexts but that sound weird to me because ApplicationDbContext inherit from IdentityDbContext.
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base( "DBContextConnString" )
{
}
}
public class DomainContext:DbContext {
public DomainContext() : base( "DBContextConnString" ) { }
public DbSet<State> States { get; set; }
protected override void OnModelCreating( DbModelBuilder modelBuilder ) {
modelBuilder.HasDefaultSchema( "Workflow" );
base.OnModelCreating( modelBuilder );
}
}
One of the The new fetures exposed by EF6 state "Multiple Contexts per Database removes the previous limitation of one Code First model per database when using Migrations or when Code First automatically created the database for you." (Read it here). But in practice is a pain to implement this or maybe i am missing something very very obvious.
My question in short, what is the way to go to keep this two different DBContexts living in armony?
After some experimentation i conclude that the more pragmatic way is to mingle both DbContext into one, so i decide to move my domain entities to IdentityDbContext.
I am just starting out on Entity Framework 4.1 Code-First. I have created my classes and DbContext, and they work perfectly fine. Right now I want to bind my ListView to my Entities, with the help of an EntityDataSource, but unfortunately it does not recognise any available connection strings! I think the providerName must be System.Data.EntityClient for it to work, but I have no concrete entity model to reference to...
I have read that an ObjectContext can be "adapted" from the DbContext, which in turn can be used to create an ObjectDataSource. I want to use my DbContext to bind to my ListView, however. Is there any way I can do this?
I have a hard time understanding your question... You want to specify the connection string when you instanciate your Context class, is that it?
You can create an overload of your constructor of your DbContext class, like
public MyContext(string connString) : base (connString)
{
Database.SetInitializer(...
...
}
Then, in a Code-First approach, you don't really need the ObjectContext except for super-advanced scenarios, and databinding isn't one of them I guess. To get to bind to a collection in your Context class, just put a property for it in a ViewModel class designed for your screen, like
public class MyViewModel
{
private MyContext _context;
public ObservableCollection<MyObject> MyObjects { get; set; }
public MyViewModel()
{
_context = new MyContext();
MyObjects = new ObservableCollection<MyObject>(_context.MyObjects.ToList());
}
}
Then you can bind your ListView against that property, given that it's referenced.
Hope it helps, otherwise please give more details.
Maybe I haven't quite get the whole thing about models. I tought that, it was probably wrong, EF framework could map any kind of class. So I did provide classes with different interfaces, with ToString() methods and so on.
I was thinking of reusable/flexible structure of classes for some kind of public organization.
For example, there are next classes
[Serializable]
public abstract class AbstractRole
{
public String Title { get; set; }
public abstract void ExecuteRole();
public abstract Decimal GetSalary();
// ToString(...) implementations and so on
}
[Serializable]
public class Employee<T> : IComparable<Employee<T>>, IFormattable where T : AbstractRole
{
private Person person;
public T Role { get; set; }
// interfaces implementations...
}
So all I wanted is to get flexibility to change employee's role in time and not to bind to its instance (avoid inheritance).
But later I read that generics are not supported by EF.
What should I do?
In case of entity framework you must provide exact type. Base classes are supported only if whole inheritance tree is mapped as well. Interfaces and generic types are not supported at all.
That means that reusable and flexible architecture is not something which can use EF.