Is it possibile to use a single transaction (on EF) with two different contexts pointing different schemas? - entity-framework

I'm currenly designing an application where I need to use two different database schemas (on the same instance): one as the application base, the other one to customize the application and the fields for every customer.
Since I read something about Repository pattern and as I've understood is possible to use two different contexts without efficiency loose, I'm now asking if I can use a single database transaction between two schemas with Entity Framework, as I'm actually doing directly on the database (SQL Server 2008-2012).
Sorry for my English an Thanks in advance!

If your connection strings are the same (which in your case will be as you have different schemas only for different contexts) then you are ok with this approach.
Basically you will have two different contexts that will be connected via the same connection string to the database and which will represent two different schemas.
using (var scope = new TransactionScope()) {
using (var contextSO = new ContextSchemaOne()) {
// Add, remove, change entities from context schema one
ContextSchemaOne.SaveChanges;
}
using (var contextST = new ContextSchemaTwo()) {
// Add, remove, change entities from context schema two
ContextSchemaTwo.SaveChanges;
}
scope.Complete();
}
I wasn't very successful in the past with this approach, and we switched to one context per database.
Further reading: Entity Framework: One Database, Multiple DbContexts. Is this a bad idea?
Maybe it's better to read something about unit of work before taking a decision about this.
You will have to do something like this: Preparing for multiple EF contexts on a unit of work - TransactionScope

Related

JPA: how to map some entities to a different schema of another database instance?

JPA: is there a way to map some entities to a schema of another database instance? e.g.,
#Entity
public class Foo {
}
#Entity
#Table(schema="schema1")
public class Bar {
}
The Bar entity is mapped to the schema1 of the same database instance. Is there a way in JPA to map it to a schema in a remote database instance? It is useful for sharing entities among multiple applications.
Can the "catalog" be used for this purpose?
What do you mean by 'remote database'?
If you use #Table(schema = "myschema", name = "bar"), Hibernate will qualify all queries with the schema name (e.g. SELECT e FROM Bar will ultimately translate to SELECT * FROM myschema.bar). If the database user you're using to connect to the DB has access to myschema.bar (whatever such a DB object is), then the query will work; if not, then the query will fail.
If you mean 'a remote DB that is a separate server', then, of course, you can only connect to the DB using one JDBC connection per persistence context. If that's your scenario, perhaps you should consult the docs of the RDBMS for ways to connect two DB instances (in Oracle, for example, you could use database links and synonyms).
Make sure that you understand the implications, though, as such a solution introduces its own class of problems (including the fact that you suddenly have implicit distributed transactions in your system).
As a side note, I'm not sure how such an approach is 'useful for sharing entities among multiple applications' or why one would even think 'sharing entities among multiple applications' is somehow useful, but I'd seriously think through the idea of integrating multiple application via shared/linked DBs. It usually introduces more problems than it solves.
If I understand well what you mean, you should use two (or more) different persistence context

Mapping DDD domain models to EF POCO

If there are two Customer domain models representing different bounded contexts (with different/overlapping fields), how are you supposed to Update this certain X bounded context Customer in the database that might be holding both those Customer domains in one POCO (or maybe Y bounded context Customer additionally uses a list of Orders of this same context)?
Also I could put it this way. How do you solve cases when domain models maps many to one with the database POCO?
Does it mean that repository would have to query db once more, but this time whole POCO object from DB, update its values accordingly and finally make the update?
It would help if you provided the 2 contexts and overlapping attributes of Customer. For the purpose of this answer Ill use the contexts: 'Sales' and 'Marketing' and the shared attribute is 'Preferred Name'
My initial thought based on the phrase 'overlapping fields' is that you need to revisit your model as you should not have 2 models responsible for a specific value otherwise you have concurrency/race conditions.
Try and think how your clients would resolve the situation in the old days of pen & paper. Who would own the 'customer' file? Would sales and marketing each have their own version, or would marketing rely on sales copy (or visa versa)?
Also, one of the most powerful aspects of DDD is it forces your persistence concerns way out into you infrastructure layers where they belong. You do not have to use EF for all your repository calls, if it easier to hand craft some sql for a specific persistence call then do it.
--Scenario 1: Overlapping field is not overlapping--
In this case, the domain experts came to realise that Sales.Customer.PreferredName and Marketing.Customer.PreferredName are independent attributes and can be different between contexts. Marketing often used the field for their cute we are you best pals campaign correspondence whilst Sales preferred to keep on file the most un-ambiguous
The CUSTOMER database table has 2 fields: PreferredNameSale and PreferredNameMarketing.
The 2 Concrete Repositories will end up looking something like:
class Sales.Repositories.ClientRepository : Domain.Sales.IClientRepository {
Update(Domain.Sales.Client salesClient) {
using (var db = new MyEfContext()) {
var dbClient = db.Client.Fetch(salesClient.Id);
dbClient.PreferredNameSales = salesClient.PreferredName;
db.SaveChanges();
}
}
}
class Marketing.Repositories.ClientRepository : Domain.Marketing.IClientRepository {
Update(Domain.Marketing.Client marketingClient) {
using (var db = new MyEfContext()) {
var dbClient = db.Client.Fetch(marketingClient.Id);
dbClient.PreferredNameMarketing = marketingClient.PreferredName;
db.SaveChanges();
}
}
}
Entity Framework should notice that only 1 field was changed and send the appropriate update client set field=newvalue where id=1 to the database.
There should be no concurrency issues when sales and marketing update their version of a single clients preferred name at the same time.
Also note that EF is providing a lot of overhead and very little value here. The same work could be completed with a simple parameterised SqlCommand.Execute()
--Scenario 2: Overlapping field is overlapping--
Your model is broken but it is too late to fix it properly. You lie to yourself that the chances of sales and marketing trying to change the preferred name at the same time is tiny and even if it happens, it should be rare that hopefully the user will blame themselves for not using the system correctly.
In this case, there is only one database field: client.PreferredName and as with scenario 1, the functions work on the same table/field:
class Sales.Repositories.ClientRepository : Domain.Sales.IClientRepository {
Update(Domain.Sales.Client salesClient) {
using (var db = new MyEfContext()) {
var dbClient = db.Client.Fetch(salesClient.Id);
dbClient.PreferredName = salesClient.PreferredName;
db.SaveChanges();
}
}
}
class Marketing.Repositories.ClientRepository : Domain.Marketing.IClientRepository {
Update(Domain.Marketing.Client marketingClient) {
using (var db = new MyEfContext()) {
var dbClient = db.Client.Fetch(marketingClient.Id);
dbClient.PreferredName = marketingClient.PreferredName;
db.SaveChanges();
}
}
}
The Obviously problem is that a save at the same time by both sales and marketing will end up with last one wins in terms of persisted data. You can try and mitigate this with lastupdated timestamps and so on but it will just get more messy and broken. Review your model and remember: DB MODEL != DOMAIN MODEL != UI View Model
Each bounded context is required to have its own database. That is it, there should be no discussion here. Violating this rule leads to severe consequences, which have been discussed many times.
Overlapping fields smell, different bounded contexts have different concerns and therefore do not require to have much data to share. The best case is when the only thing you share is the aggregate identity. If in your world you have one Customer that have different concerns handled by two different bounded contexts, you can use one CustomerId value for both bounded contexts.
If you really need to sync some data, you need to have it in both models, therefore in both persistent stores (I intentionally avoid the word database here) and you can sync the data using domain events. This is very common.

Entity Framework Repository Design, multiple instances of IUnitOfWork in multi-level loop

i am using Entity Framework and repository with unit of work design pattern.
Sometimes with my unit of work, I am making other calls to a different service.
This service in turn is making its own unit of work instance, for example:
ISettingsService settingsService = UnityContainer.Resolve<ISettingService>();
using (IUnitOfWork unitOfWork = UnitOfWorkFactory.CreateUnitOfWork())
{
List<Company> companies = unitOfWork.CompaniesRepository.GetAll();
foreach(Company company in companies)
{
settingsService.SaveSettings(company, "value to set");
company.Processed = DateTime.UtcNow();
}
unitOfWork.Save();
}
// ISettingsService.SaveSettings code in another module...
ISettingsService.SaveSettings(Company company, string value)
{
using (IUnitOfWork unitOfWork = UnitOfWorkFactory.CreateUnitOfWork())
{
Setting setting = new Setting();
setting.CompanyID = company.CompanyID;
setting.SettingValue = value;
unitOfWork.Insert(setting);
unitOfWork.Save();
}
}
The above code does work, but i have to reference ID's explicitly rather than attaching the company object (it would throw an error as it is already being tracked by the other unit-of-work in the other service).
As far as I can tell I see 3 ways of this happening:
1) Use the code as-is with service layers creating their own unit-of-work instances, any other references to other entity's are done on a primary key basis (procedures to set values should be passed by primary key object value, i.e. int customerID).
The bad side to this is potentially more hits to the database, and if the entity primary key type changed, i would need to change all service layer references for the ID field.
__
2) Have service layers accept entity objects as references. This would be nice as i could pass objects around.
The bad side to this is that entities must not be referenced from any other context and must be attached to context to where it will be used. In a loop, the entity will most probably already be attached.
__
3) Pass in unit-of-work instantiations to other service layers to they can use the existing unit-of-work instead of instantiating their own.
Not sure there is a downside to this other than having to pass around a unit-of-work reference, the upside would be the ability to reference objects without having to attach them or worry if they are already attached.
__
In summary, I need to standardize on one access design, and would appreciate recommendations on what one i should choose.
In addition is there anything with transactions that i need to be concerned about or is EntityFramework with the unit-of-work design pattern implementing a form of transactional processing implicitly as changed are only committed on context.Save(), or am i mistaken?
Thanks,
Chris
You have a few options amongst them:
Have different services pass out dettached entities (its entities), perhaps even DTOs that are not entities, then have each service translate them to its entities (or use primary keys).
Each service can create its own content and use its own EDMX or a shared EMDX (or even several EDMXs).
If the services are using the same EDMX, then inject the same context into them (you can wrap it behind and interface so that they don't expose EF).
If the services don't use the same EDMX, either:
3.1. Go with option 1, using different entities for different services (or DTOs).
You can "share" tables between the EDMXs using different entities or use views to "tables from external domains" to reflect a read-only version of tables to other domains.
3.2. Create a master EDMX by merging the EDMXs into one big one (see this question for details)
Changes are applied only when calling context.AcceptChanges(), so you can save changes to multiple contexts, then accept changes in each after all the saves have completed.

Entity framework 4 and multiple database

Something changes or it still not support this?
For example join database1.dbo.Users and database2.dbo.Addresses
I actually did find a way to make an EF model span multiple databases if your database supports Synonyms. Basically you setup Synonyms to Database2 on Database1, create separate edmx models for each, then merge the XML
I posted the exact steps to make an edmx file span multiple databases here if you're interested, along with a script to do the merge for you whenever something changes.
I think what ais asked is if you can join tables from different databases, not different providers, resulting in one entity mapped to two or more tables or views from different databases.
If you think about it, when you create a EDM model with Visual Studio it ask you to give an existing database, and when finished creating the model, it generates an EF connection string, that internally address to the given underlying database connection string.
E.g: metadata=res:///EFTestModel.csdl|res:///EFTestModel.ssdl|res:///EFTestModel.msl;provider=System.Data.SqlClient;provider connection string="Data Source=.\;Initial Catalog=EFTest;Integrated Security=True;MultipleActiveResultSets=True"*
So each model matches only a database, only a connection string.
EF4 still does not support creating one conceptual model which works with N storage models. At least this is not supported with any built-in provider. Perhaps in the future this could be done through a new provider that combines the support of many storages (from the same providers or different).
I havent done enough research on it, but perhaps Windows Server AppFabric (Codename Velocity) could be the bridge to go through this gap.
Note: I have tried even editing manually the xml for the EDM (edmx) to insert a second element inside the <edmx:StorageModels> tag but it does not match the EDM XML Schema so VS warns about it:
Error 10021: Duplicated Schema element encountered.
Rafa Ortega
MAP2010
See answer to similar question:
Entity Framework - Inserting entity with multiple models and databases

How to run two Entity Framework Contexts inside TransactionScope without MSDTC?

This problem is not readily reproducible in a simple example here but was wondering if anyone has any experience and tips, here is the issue:
using Entity Framework
have many points in application where (1) data is written to some entity table e.g. Customer, (2) data is written to history table
both of these actions use Entity Framework, HOWEVER, they use different contexts
these actions need to be both in one transaction: i.e. if one fails to write, the other should not write, etc.
I can wrap them with a TransactionScope,
like this:
using (TransactionScope txScope = new TransactionScope()) {
...
}
but this gives me:
Microsoft Distributed Transaction Coordinator (MSDTC) is disabled for
network transactions.
Our database admin has told me that MSDTC is disabled by choice and can not be installed.
Hence I am making changes trying to create my own EntityConnection with a MetadataWorkspace with the idea that each context will use the same EntityConnection. However, this is proving near impossible trying to get it to work, e.g. currently I continue to get the above error even though theoretically both contexts are using EntityConnection. It's difficult to understand where/why Entity Framework is requiring the MSDTC for example.
Has anyone gone down this road before, have experience or code examples to share?
Well, the problem is quite easy.
If you are using sql server 2008 you should not have that problem because you have promotable transaction, and as .NET knows that you are using the same persistence store (the database) it wont promote it to DTC and commit it as local. look into promotable transaction with sql server 2008.
As far as I know Oracle is working in its driver to support promotable transactions, but I do not know the state, MS oracle driver does not support it.
http://www.oracle.com/technology/tech/windows/odpnet/col/odp.net_11.1.0.7.20_twp.pdf
If you are using a driver that do not support promotable transactions it is impossible for .NET to use local transaction doing two connections. You should change your architecture or convince the database admin for installing MSDTC.
I had a similar problem with SQL 2008, Entity Framework.
I had two frameworks defined (EF1, and EF2) but using identical connection strings to a sql 2008 database.
I got the MSDTC error above, when using nested "usings" across both.
eg the code was like this:
using (TransactionScope dbContext = new TransactionScope())
{
using (EF1 context = new EF1())
{
// do some EF1 db call
using (EF2 context2 = new EF2())
{
// do some EF2 db call
}
}
dbContext.Complete();
}
It wasnt as simple as this, because it was split across several methods, but this was the basic structure of "usings".
The fix was to only open one using at a time. No MTDSC error, No need to open distributed transactions on db.
using (TransactionScope dbContext = new TransactionScope())
{
using (EF1 context = new EF1())
{
// do some EF1 db call
}
using (EF2 context2 = new EF2())
{
// do some EF2 db call
}
dbContext.Complete();
}
I think that what you need to do is to force your contexts to share single database connection. You will be able then to perform these two operations against two different contexts in single transaction. You can achieve this by passing one EntityConnection object to both of your context's constructors. Of course this approach will require you to pass this object to methods which update DB.
I have recently blogged about creating database context scope which will make using multiple EF contexts and transactions easier.