A bit of context: we use several databases, among which DB_A and DB_B. There is a table in DB_B, called TableB, whose data are based on those in table TableA from DB_A.
Class MaintainDB_B has a method MaintainTableB() that looks up table TableA in database DB_A and sets data in TableB in database DB_B to match the contents of TableA, creating, updating or deleting data rows as needed.
Accessing both databases is done through a specific ControllerDB class from a custom DAL method library, that has methods Select(), Insert(), Update(), and Delete(). ControllerDB implements the interface IControllerDB.
Here is the simplified code:
Main project
public class BasicWorkingClass
{
public IControllerDB ControllerDB_A { get; set; }
public IControllerDB ControllerDB_B { get; set; }
// Other IControllerDB properties, accessing other databases
}
public class MaintainDB_B : BasicWorkingClass
{
public void MaintainTableB()
{
// Uses ControllerDB_A.Select() to list the contents of TableA in database DB_A
// Then uses ControllerDB_B.Select() to loop through TableB from database DB_B
// Using the contents of TableA and TableB, uses ControllerDB_B.Insert(),
// ControllerDB_B.Update() and ControllerDB_B.Delete() to make data in TableB
// match that in TableA
}
// Other methods maintain other tables in DB_B
}
Testing project
[TestFixture]
public class TestMaintainDB_B
{
public MaintainDB_B MaintainDB_B_Instance;
protected Mock<IControllerDB> MockControllerDB;
protected List<ClassLikeTableA> ListTableA;
[Setup]
public void ResetStuffBeforeTesting()
{
MaintainDB_B_Instance = new MaintainDB_B();
MockControllerDB = new Mock<IControllerDB>();
}
[Test]
public void TestMaintainTableB()
{
MockControllerDB.Setup(co => co.Select(It.IsAny<ClassLikeTableA>))
.Returns(ListTableA);
// Four other Setup() calls mock Select, Insert, Update and Delete targeting TableB
// It works with just one Mock<IControllerDB> object because all four methods have a
// parameter that indicates which table is targeted as seen above
MaintainDB_B_Instance.ControllerDB_A = MockControllerDB.Object;
MaintainDB_B_Instance.ControllerDB_B = MockControllerDB.Object;
// Start testing proper
}
}
Recently, a new person was added to the team, and convinced us that BasicWorkingClass having IControllerDB properties is a code smell because some classes that inherit from BasicWorkingClass have no use for ControllerDB_A and others have none for ControllerDB_B.
So we've been replacing those properties with using (IControllerDB z_objLocalController = new ControllerDB()) blocks in the classes that needed corrections or evolutions.
Now MaintainDB_B needs corrections, so I've started replacing ControllerDB_A as mentioned.
The issue is, how do I keep mocking the database access?
Move every database access occurrence in its own public method, then mock each method. I understand that it's another code smell because those methods are supposed to be used only inside the class.
Create IControllerDB properties in MaintainDB_B and use them instead of those from BasicWorkingClass. I fear that it's another code smell too since, well, they aren't supposed to be public either.
Something else?
Related
I have class with the following struct:
public class student
{
public int Id {get;set;}
public string name {get;set;}
}
I use the following configuration on model creation to match table column with class in the database based on parameter for example I have ,
16_student,17_student,18_student..... all these tables match the student class
public class studentConfiguration : EntityTypeConfiguration<Models.student>
{
public studentConfiguration (string SchoolId)
{
this.ToTable(SchoolId + "_student");
}
}
The previous function work fine with existing Tables , but how i can force the EF to create new table based on new parameter
in the other word i need if i pass parameter not exist let's say schoolId = 55 new table should be created with the name 55_student if not exist
I Enable Automatic migration now and the tables created successfully when it was not exists but the problem now when I add new school with id 56 the previous tables deleted so i can only add one table each time
is there any where to prevent migration from call delete for these tables just create ??
If I understand correctly, you have a database table with a table that has a name that is composed from several values of variables. You also hava a DbSet<TEntity> in your DbContext, and you want to tell entity framework that this DbSet is modeled in your database in a table that has this composed name.
Seeing your advanced usage of class EntityTypeConfiguration I assume that you know that this is done in function DbContext.OnModelCreating
The raison d`ĂȘtre of DbContext is to connect your entity framework classes to the actual database that your classes use. The proper way to model your database would be in this class.
Apparently your override of 'DbContext.OnModelCreating' creates a StudentConfiguration object. This object will do the actual configuring of the Student entity.
You probably will do this for several entities of your database. All these configurations will need similar information. One of them is the name of the table, others could be the maximum length of certain strings, or the precision of decimals etc.
The proper way to do this, is to give your StudentConfiguration an object (o an interface) that contains this information. The whole idea is similar to the factory design pattern:
interface ISchoolRequirements
{
public string StudentTableName {get;}
... // other items that differ per school
}
class MySchoolRequirements : ISchooRequirements
{
... // properties needed to create a StudentTableName
// the function that composes the StudentTableName from the properties
private string CreateStudentTableName() {...}
// implementation of ISchoolRequirements
public string StudentTableName {get{return this.CreateStudentTableName(); }
}
public class studentConfiguration : EntityTypeConfiguration<Models.student>
{
public studentConfiguration (ISchoolRequirement schoolRequirements)
{
this.ToTable(schoolRequirements.StudentTableName);
... // other configuration items
}
}
Your DbContext with OnModelCreating:
class MyDbContext : DbContext
{
ISchoolRequirements SchoolRequirements {get; set;}
public DbSet<Student> Students {get; set;}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// if no school requirements set, use default school requirements:
ISchoolRequirements schoolRequirement = this.SchoolRequirements ??
CreateDefaultSchoolRequirements();
// create the configurations:
modelBuilder.Configurations.Add(new StudentConfiguration(schoolRequirements));
modelBuilder.Configurations.Add(new TeacherConfiguration(schoolRequirements));
modelBuilder.Configurations.Add(new ClassRoomConfigurations(schoolRequirments));
... // etc
}
}
The advantage is that the creator of your DbContext has full control on the naming of the tables, the maximum size of certain strings, the precision of decimals, the type of DateTime etc. If the user of your DbContext does not need this control, some default configuration is used. You could even decide to read this default configuration from a configuration file
I'm trying to develop a messeging system to my mvc application using mvc 5. I have tables called Event, EventUser, EventObject. Each of those tables have following;
Event
ID
CreatedBy
StartTime
IsShared
Budget
EventUser
EventID
UserID
IsAccepted
EventObject
EventID
ObjectID
in my messageController i have the index method which receive the parameter of the user id.i need to display every event that user has invited using this method..
namespace MvcApp.Controllers
{
public class MessageController : Controller
{
private EPlannerDatabaseEntities db = new EPlannerDatabaseEntities();
// GET: /Message/
public ActionResult Index(int UId)
{
/* linq expressions */
return View();
}
}
}
when the parameter has passed in, i want to;
*Select from EventUser table where UID=UserID and join the result with Event and EventObject tables by using EventID attribute.
*Finally by using the final result i need to display every event's infomation that user has invited; like CreatedBy , StartTime, Budget,other users,objects etc..
i'm new to mvc and viewmodel concept.I heard that viewmodel concept can help with these situations.can i overcome this problem by using viewmodel concept.if yes what are the things i need to add in view model?? otherwise what are the other ways to do this?
one way i can see of doing this is creating a custom return object and using EF to join all the tables together. Example
public class MyObject{
public DateTime DateCreated{get;set}
// add remaining properties here
// properties to get back
}
then in code you would use Entity Framework to create a joined data set into a nice list of objects. Example:
var results = (from b in bla join bla2 in (Some Second Query Here)
from SomeSecondQueryHere
where cond1 and cond2 Select new MyObject{
// add properties in here})
where you would replace the bla and bla2,etc with respective table names needed. Then all you need to do is
return View(results);
And the changes will be accessible in the View
If you question is regarding querying with an ORM like Entity Framework, you need to post your entities, not your table schemas. The whole purpose of an ORM is to abstract away the underlying database structure, so while the schema will often be similar to the entity class, it can also be quite different. As a result, I'll have to make assumptions about your entity classes.
To query everything, you just need something like the following:
var events = db.Events.Where(m =>
m.EventUsers.Any(u => u.UserID == UId && u.IsAccepted)
).Include(m => m.EventObjects);
That assumes entity classes along the lines of:
public class Event
{
...
public virtual ICollection<EventObject> EventObjects { get; set; }
public virtual ICollection<EventUser> EventUsers { get; set; }
}
public class EventUser
{
...
public int UserID { get; set; }
public bool IsAccepted { get; set; }
}
You end up with an enumerable of Event. If you need to access the EventObjects for an individual event, you have to use the appropriate collection property. For example:
foreach (var item in events)
{
foreach (var obj in item.EventObjects)
{
// do something with `obj` (an invidual `EventObject` instance)
}
}
If you need the actual User object, you're better object querying that first and including related Events and EventObjects:
var user = db.Users.Include("EventUsers.Event.EventObjects").SingleOrDefault(m => m.UserID == UId);
That assumes entities like:
public class User
{
...
public virtual ICollection<EventUser> EventUsers { get; set; }
}
public class EventUser
{
...
public virtual Event Event { get; set; }
}
public class Event
{
...
public virtual ICollection<EventObject> EventObjects { get; set; }
}
With that method, however, there's no way to filter the included Events by whether they're accepted or not. There's a potential way around that, but it requires disabling lazy-loading of EventUsers entirely and complicates querying the information you need. If you need to go that route, see: https://msdn.microsoft.com/en-us/data/jj574232.aspx#explicitFilter.
Otherwise, you can just exclude non-accepted events before iterating over the collection:
var events = user.EventUsers.Where(m => m.IsAccepted).Select(m => m.Event);
Really you don't need a view model, per se, for any of this. As you can either pass the lists of events (which will include any related EventObjects) or the the single user instance (which includes related events and related EventObjects) directly to your view.
A very high level description of how to solve your scenario using Entity Framework would be something like this:
First you've got to create a series of entity data objects that will represent your tables in the EF data model using EF Code first techniques.
Then you create DbContext objects with DbSets for your previously created entities.
Then you create at least one Service class that will have a property representing DbContext and a set of methods encapsulating Linq queries to your entities.
In the MVC controller you call an instance of Service that you previously create and assign it to a property ant Controller's construction time. Finally, in the Action method you should call the correct Service method and pass any result to the view.
( I am assuming this is a small Ad-Hoc system with a handful of tables , an elaborate System with production quality would require using IoC techniques).
Using different languages (php, .net) and frameworks(zf2), I fetch data from a database and store it into a model class. Every property of this class maps to a column on the database.
So if I have a table: tbl_user: user_id, user_name.
I would have a class: +User: +string user_id, +string user_name.
One of the TDD principles say: "Write some code that causes the test to pass"
Do I need to test the model too? Because it looks to me to be a really redundant test.
No. If the class only contains Properties / Fields and doesn't contain any logic, there is no need to test it. If you're concerned about code coverage, these classes will be 'tested' by the tests for whichever class consumes them.
For example:
public class DomainObject
{
public int Id{ get; set; }
public string Name {get;set; }
}
public class BusinessLogic
{
public void DoSomethingBusinessLike(DomainObject do)
{
//stuff happens
}
}
It is not necessary to test DomainObject directly, it is implicilty tested when you create tests for BusinessLogic.
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.
This is a very weird architecture. Please bear with me.
We have an existing tiered application (data, logic/service, client).
The latest requirement is that the service layer should access two data sources!!!! (no other way around)
These two data sources have the same DB schema.
As with most tiered architectures, we have read and write methods like:
IEnumerable<Product> GetAllProducts(),
Product GetProductById(ProductKey id),
IEnumerable<Product> FindProductsByName(string name)
the product DTOs are:
class Product
{
public ProductKey Key { get; set;}
...
}
class ProductKey
{
public long ID { get; }
}
We narrowed it down to two possible solutions:
Alternative 1:
Add a parameter into the read methods so that the service knows what DB to use like so:
Product GetProductById(ProductKey id, DataSource dataSource)
DataSource is an enumeration.
Alternative 2 (my solution):
Add the DataSource property to the key classes. this will be set by Entity Framework when the object is retrieved. Also, this will not be persisted into the db.
class ProductKey
{
public long ID { get; }
public DataSource Source { get; } //enum
}
The advantage is that the change will have minimal impact to the client.
However, people dont like this solution because
the DataSource doesn't add business value. (My response is that
the ID doesn't add business value either. Its a surrogate key. Its
purpose is for tracking the persistence)
The children in the object graph will also contain DataSource which is redundant
Which solution is more sound? Do you have other alternatives?
Note: these services are used everywhere.
What I would suggest is door number 3:
[||||||||||||||]
[|||||||||s! ]
[||||nerics! ]
[ Generics! ]
I use a "dynamic repository" (or at least that is what I have called it). It is setup to be able to connect to any datacontext or dbset while still being in the same using block (i.e. without re-instantiation).
Here is a snippet of how I use it:
using (var dr = new DynamicRepo())
{
dr.Add<House>(model.House);
foreach (var rs in model.Rooms)
{
rs.HouseId = model.House.HouseId;
dr.Add<Room>(rs);
}
}
This uses the "default" dbcontext that is defined. Each one must be defined in the repository, but not instantiated. Here is the constructor I use:
public DynamicRepo(bool Main = true, bool Archive = false)
{
if (Main)
{
this.context = new MainDbContext();
}
if (Archive)
{
this.context = new ArchiveDbContext();
}
}
This is a simplified version where there are only two contexts. A more in depth selection method can be implemented to choose which context to use.
And then once initialized, here would be how the Add works:
public void Add<T>(T te) where T : class
{
DbSet<T> dbSet = context.Set<T>();
dbSet.Add(te);
context.SaveChanges();
}
A nice advantage of this is that there is only one spot to maintain the code for interacting with the database. All the other logic can be abstracted away into different classes. It definitely saved me a lot of time to use a generic repository in this fashion - even if I spent some time modifying it at first.
I hope I didn't misunderstand what you were looking for, but if you are trying to have one repository for multiple data sources, I believe this is a good approach.