Entity Framework with multiple edmx - c#

Let's say I have in my database multiple db schema for example : HumanRessources and Inventory.
In each of those schema contains multiple tables. Do you usually split your DB into multiple edmx or usually just put everything in one single edmx?
I was thinking about creating a edmx for each schema, but wondering how this will impact a unitorwork pattern. Reading through some articles, the ObjectContext will be the unitofwork. By defining 2 edmx, I will end up with 2 ObjectContext : HumanRessourceContext and InventoryContext, meaning each will will be a unitofwork. What if I want all modification made to an entity in the humanressource and an entity in the inventorycontext to be ATOMIC, can this be achieve with the unitofwork pattern?

While this isn't an endorsement of splitting up the database by schema into EDMX's, you can make the updates atomic by using a TransactionScope:
using(TransactionScope trans = new TransactionScope())
{
using(HumanResources hr = new HumanResources())
{
//...
hr.SaveChanges();
}
using(Inventory inv = new Inventory())
{
//...
inv.SaveChanges();
}
trans.Complete();
}
Obviously you can rearrange your context objects however you like (if you need to use them both at the same time, for instance) and you can alter the transaction isolation level to whatever is appropriate, but this should give you what you need to know in order to make your database changes atomic.

If your Inventory and HumanResources tables don't have any relationships between them, splitting up the tables into two edmx files is fine, though I don't know what benefit it would offer. If they do have direct or indirect relationships, you will run into problems trying to use those relationships. The simplest solution is to use a single EDM.

Related

Live Transfer of data from one provider to another in Entity Framework

I apologise if this has been asked already, I am struggling greatly with the terminology of what I am trying to find out about as it conflicts with functionality in Entity Framework.
What I am trying to do:
I would like to create an application that on setup gives the user to use 1 database as a "trial"/"startup" database, i.e. non-production database. This would allow a user to trial the application but would not have backups etc. in no way would this be a "production" database. This could be SQLite for example.
When the user is then ready, they could then click "convert to production" (or similar), and give it the target of the new database machine/database. This would be considered the "production" environment. This could be something like MySQL, SQLServer or.. whatever else EF connects to these days..
The question:
Does EF support this type of migration/data transfer live? Would it need another app where you could configure the EF source and EF destination for it to then run through the process of conversion/seeding/population of the data source to another data source?
Why I have asked here:
I have tried to search for things around this topic, but transferring/migration brings up subjects totally non-related, so any help would be much appreciated.
From what you describe I don't think there is anything out of the box to support that. You can map a DbContext to either database, then it would be a matter of fetching and detaching entities from the evaluation DbContext and attaching them to the production one.
For a relatively simple schema / object graph this would be fairly straight-forward to implement.
ICollection<Customer> customers = new List<Customer>();
using(var context = new AppDbContext(evalConnectionString))
{
customers = context.Customers.AsNoTracking().ToList();
}
using(var context = new AppDbContext(productionConnectionString))
{ // Assuming an empty database...
context.Customers.AddRange(customers);
}
Though for more complex models this could take some work, especially when dealing with things like existing lookups/references. Where you want to move objects that might share the same reference to another object you would need to query the destination DbContext for existing relatives and substitute them before saving the "parent" entity.
ICollection<Order> orders = new List<Order>();
using(var context = new AppDbContext(evalConnectionString))
{
orders = context.Orders
.Include(x => x.Customer)
.AsNoTracking()
.ToList();
}
using(var context = new AppDbContext(productionConnectionString))
{
var customerIds = orders.Select(x => x.Customer.CustomerId)
.Distinct().ToList();
var existingCustomers = context.Customers
.Where(x => customerIds.Contains(x.CustomerId))
.ToList();
foreach(var order in orders)
{ // Assuming all customers were loaded
var existingCustomer = existingCustomers.SingleOrDefault(x => x.CustomerId == order.Customer.CustomerId);
if(existingCustomer != null)
order.Customer = existingCustomer;
else
existingCustomers.Add(order.Customer);
context.Orders.Add(order);
}
}
This is a very simple example to outline how to handle scenarios where you may be inserting data with references that may, or may not exist in the target DbContext. If we are copying across Orders and want to deal with their respective Customers we first need to check if any tracked customer reference exists and use that reference to avoid a duplicate row being inserted or throwing an exception.
Normally loading the orders and related references from one DbContext should ensure that multiple orders referencing the same Customer entity will all share the same entity reference. However, to use detached entities that we can associate with the new DbContext via AsNoTracking(), detached references to the same record will not be the same reference so we need to treat these with care.
For example where there are 2 orders for the same customer:
var ordersA = context.Orders.Include(x => x.Customer).ToList();
Assert.AreSame(orders[0].Customer, orders[1].Customer); // Passes
var ordersB = context.Orders.Include(x => x.Customer).AsNoTracking().ToList();
Assert.AreSame(orders[0].Customer, orders[1].Customer); // Fails
Even though in the 2nd example both are for the same customer. Each will have a Customer reference with the same ID, but 2 different references because the DbContext is not tracking the references used. One of the several "gotchas" with detached entities and efforts to boost performance etc. Using tracked references isn't ideal since those entities will still think they are associated with another DbContext. We can detach them, but that means diving through the object graph and detaching all references. (Do-able, but messy compared to just loading them detached)
Where it can also get complicated is when possibly migrating data in batches (disposing of a DbContext regularly to avoid performance pitfalls for larger data volumes) or synchronizing data over time. It is generally advisable to first check the destination DbContext for matching records and use those to avoid duplicate data being inserted. (or throwing exceptions)
So simple data models this is fairly straight forward. For more complex ones where there is more data to bring across and more relationships between that data, it's more complicated. For those systems I'd probably look at generating a database-to-database migration such as creating INSERT statements for the desired target DB from the data in the source database. There it is just a matter of inserting the data in relational order to comply with the data constraints. (Either using a tool or rolling your own script generation)

Migrating Db and Entity framework

I have to take data from an existing database and move it into a new database that has a new design. So the new database has other columns and tables than the old one.
So basically I need to read tables from the old database and put that data into the new structure, some data won't be used anymore and other data will be placed in other columns or tables etc.
My plan was to just read the data from the old database with basic queries like
Select * from mytable
and use Entity Framework to map the new database structure. Then I can basically do similar to this:
while (result.Read())
{
context.Customer.Add(new Customer
{
Description = (string) result["CustomerDescription"],
Address = (string) result["CuAdress"],
//and go on like this for all properties
});
}
context.saveChanges();
I think it is more convenient to do it like this to avoid writing massive INSERT-statements and so on, but is there any problems in doing like this? Is this considered bad for some reason that I don't understand. Poor performance or any other pitfalls? If anyone has any input on this it would be appreciated, so I don't start with this and it turns out to be a big no-no for some reason.
Something that you could perhaps also try, is merely to write a new DBContext class for the new target database.
Then simply write a console application with a static method which copies entities and properties from the one context to the other.
This will ensure that your referential integrity remains intact and saves you a lot of hassle in terms of having to write SQL code, since EF does all the heavy lifting for you in this regard.
If the dbContext contains a lot of entity dbsets I recommend that you use some sort of automapper.
But, this depends on the amount of data that you are trying to move. If we are talking terrabytes, I would rather suggest you do not take this approach.

Entity Framework updating two databases

As I've mentioned in a couple other questions, I'm currently trying to replace a home-grown ORM with the Entity Framework, now that our database can support it.
Currently, we have certain objects set up such that they are mapped to a table in our internal database and a table in the database that runs our website (which is not even in the same state, let alone on the same server). So, for example:
Part p = new Part(12345);
p.Name = "Renamed part";
p.Update();
will update both the internal and the web databases simultaneously to reflect that the part with ID 12345 is now named "Renamed part". This logic only needs to go one direction (internal -> web) for the time being. We access the web database through a LINQ-to-SQL DBML and its objects.
I think my question has two parts, although it's possible I'm not asking the right question in the first place.
Is there any kind of "OnUpdate()" event/method that I can use to trigger validation of "Should this be pushed to the web?" and then do the pushing? If there isn't anything by default, is there any other way I can insert logic between .SaveChanges() and when it hits the database?
Is there any way that I can specify for each object which DBML object it maps to, and for each EF auto-generated property which property on the L2S object to map to? The names often match up, but not always so I can't rely on that. Alternatively, can I modify the L2S objects in a generic way so that they can populate themselves from the EF object?
Sounds like a job for Sql Server replication.
You don't need to inter-connect the two together as it seems you're saying with question 2.
Just have the two separate databases with their own EF or L2S models and abstract them away using repositories with domain objects.
This is the solution I ended up going with. Note that the implementation of IAdvantageWebTable is inherited from the existing base class, so nothing special needed to be done for EF-based classes, once the T4 template was modified to inherit correctly.
public partial class EntityContext
{
public override int SaveChanges(System.Data.Objects.SaveOptions options)
{
var modified = this.ObjectStateManager.GetObjectStateEntries(EntityState.Modified | EntityState.Added); // Get the list of things to update
var result = base.SaveChanges(options); // Call the base SaveChanges, which clears that list.
using (var context = new WebDataContext()) // This is the second database context.
{
foreach (var obj in modified)
{
var table = obj.Entity as IAdvantageWebTable;
if (table != null)
{
table.UpdateWeb(context); // This is IAdvantageWebTable.UpdateWeb(), which calls all the existing logic I've had in place for years.
}
}
context.SubmitChanges();
}
return result;
}
}

Same model in more than one table

I have a class, suppose it's called EntityModel, and I want to make three different tables with the same columns, as defined in EntityModel. Let's call the tables tbPast, tbPresent and tbFuture. I want also to access them separetely in the Entity DbContext:
using (var db = new MyContext())
{
var element = db.Past.Find(id);
db.Past.Remove(element);
db.Present.Add(element);
db.SaveChanges();
}
The main purpose of having three tables is performance: the table will have millions of rows, and the most important is the Present, with dozens of rows. Most queries will be made in the Present table.
What is the best way to do this? Implementing three models with the same properties doesn't seem right for me.
I'm using Entity Framework, with the Code First approach, along with ASP.NET MVC 3.
You can't use the same model to generate separate tables w/ EF code-first. If you need to have some sort of grouping, use a Discriminator field and assing it any of the values: Past Present Future.
Edit:
Similar effect can be achieved through table-per-concrete type inheritance. Thus each type will have it's own table and can share most (if not all) of the fields.

Saving a single entity instead of the entire context

I've run into a scenario where I essentially need to write the changes of a child entity of a one-to-many association to the database, but not save any changes made to the parent entity.
The Entity Framework currently deals with database commits in the context scope (EntityContext.SaveChanges()), which makes sense for enforcing relationships, etc. But I'm wondering if there is some best practice or maybe a recommended way to go about doing fine-grained database commits on individual entites instead of the entire context.
Best practices? Do you mean, besides, "Don't do it!"?
I don't think there is a best practice for making an ObjectContext different than the state of the database.
If you must do this, I would new up a new ObjectContext and make the changes to the child entity there. That way, both contexts are consistent.
I have a similar need. The solution I am considering is to implement wrapper properties on all entities that store any property changes privately without affecting the actual entity property. I then would add a SaveChanges() method to the entity which would write the changes to the entity and then call SaveChanges() on the context.
The problem with this approach is that you need to make all your entities conform to this pattern. But, it seems to work pretty well. It does have another downside in that if you make a lot of changes to a lot of objects with a lot of data, you end up with extraneous copies in memory.
The only other solution I can think of is to, upon saving changes, save the entity states of all changed/added/deleted entities, set them to unmodified except the one you're changing, save the changes, and then restore the states of the other entities. But that sounds potentially slow.
This can be accomplished by using AcceptAllChanges().
Make your changes to the parent entity, call AcceptAllChanges(), then make your changes to the related Entities and call SaveChanges(). The changes you have made to the parent will not be saved because they have been "committed" to the Entity but not saved to the database.
using (AdventureWorksEntities adv = new AdventureWorksEntities())
{
var completeHeader = (from o in adv.SalesOrderHeader.Include("SalesOrderDetail")
where o.DueDate > System.DateTime.Now
select o).First();
completeHeader.ShipDate = System.DateTime.Now;
adv.AcceptAllChanges();
var details = completeHeader.SalesOrderDetail.Where(x => x.UnitPrice > 10.0m);
foreach (SalesOrderDetail d in details)
{
d.UnitPriceDiscount += 5.0m;
}
adv.SaveChanges();
}
This worked for me. Use the ChangeTracker.Clear() method to clear out changes for other entities.
_contextICH.ChangeTracker.Clear();
var x = _contextICH.UnitOfMeasure.Attach(parameterModel);
x.State = (parameterModel.ID != null) ? Microsoft.EntityFrameworkCore.EntityState.Modified : Microsoft.EntityFrameworkCore.EntityState.Added;
_contextICH.SaveChanges();

Categories

Resources