I've several databases that contains the exact same base tables with identical design. Now I need to be able to access a base table from any one of those database.
Is there any way to create a common interface that can still utilize the power of Linq2Sql? I was thinking that I would have a factory that created a data context for that chosen database which I could afterwards query:
string university = "SomeUniversity";
var database = UniversityDataContextFactory.Get(university);
var user = database.Users.Where(u => u.Id== id).First();
This, however, would require the data contexts returned from the individual databases to implement a shared interface and very possibly also to share data classes.
If the database schemas are identical then you only need one set of data classes - the only difference between one "data context" and another will be the connection string.
This is where things get a bit more fun. If you are explicitly creating the data context - as in your factory example - then there's not an issue so long as you have a means to provide/create the appropriate connection sting as there is a constructor for a data context that takes a connection string as a parameter. However if you're implicitly creating one (in back of something like dynamic data) then I'm not sure what you'd need to do (I've dealt with this on a per application instance basis but not for multiple connections in a single application).
The key to remember is that the data connection string in your .config is the default but not necessarily the only connection string that you can use with a data context.
Related
I have been reading several examples of Sitecore DataProvider implementation on single database and single table (using the config file parameters to specify particular table and columns trying to integrate with). Just wonder if it is possible to implement the dataprovider working on multiple tables instead of just one. Couldn't find any examples on this, just asking for any ideas or possibilities.
First problem I encounter when I try to deal with multiple tables is to override GetItemDefinition method. Since this method returns only one item definition and needs to know which particular table it will get the item information from. (This is specified in the config file if just dealing with one table). Basically I am looking for a way to switch (dynamically) between tables without changing the config file params every time.
If you're creating a custom data provider then then implemetation is left entirely up to you. If you have been following some of the examples such, such as the Northwind Dataprovider then as you state the implementation acts on a single database as specified in config. But you can specify whatever you need in the methods that you implement, and run logic to switch the select statement you call in the methods such as GetItemDefinition() and GetItemFields(). You can see in the Northwind exmaple that the SQL query is dynamically built:
StringBuilder sqlSelect = new StringBuilder();
sqlSelect.AppendFormat("SELECT {0} FROM {1}", nameField, table);
If you are building a read-only dataprovider then you might be able to make use of SQL Views, allowing you to write a query to combine the results from several tables using UNION operator. As long as each record has a unique ID across tables (i.e. if you are using GUIDs as the ID) then this should work fine.
I am trying to create driver for linqpad and have question:
When I am creating DynamicDataContextDriver, I must create class TypedDataContext.
What I should put in it?
How will it be populated?
Can I control how will it be populated?
If I use object database here, is there something that I must bear in mind?
I found some answer here, but I can not find there all the above answers.
A typed data context is simply a class with properties/fields suitable for querying. Those properties/fields will typically return IEnumerables or IQueryables. For example:
public class TypedDataContext
{
public IEnumerable<Customer> Customers { get { ... } }
public IEnumerable<Order> Orders { get { ... } }
...
}
When you use Visual Studio to create a new item of kind "LINQ to SQL classes" or "ADO.NET Entity Data Model", Visual Studio creates a typed data context for you which is an excellent example of what LINQPad expects. A typed data context can also expose methods (e.g., to map stored procedures or functions) - in fact it can expose anything that makes sense to the end user.
When you execute a query in LINQPad that has a connection, LINQPad subclasses the typed data context associated with the connection so that the query has access to all of its fields/properties. This is why Customers.Dump() is a valid query - we can just access Customers without having to instantiate the typed data context first.
A LINQPad driver can work in one of two ways. Either it can act like Visual Studio and build the typed data context automatically and on the fly (dynamic data context driver), or it can extract a typed data context from an existing assembly provided by the user (static data context driver). When you add a connection in LINQPad, you'll notice that the drivers are listed in two list boxes (Build data context automatically = dynamic driver, and Use a typed data context from your own assembly = static driver).
The typed data context is instantiated whenever a query executes. Because its properties typically return lazily evaluated IEnumerables/IQueryables, it's not helpful to think of "populating" it. However, it will need to know how to access an underlying data source, and this is done by passing arguments into the constructor.
LINQPad normally keeps the query's application domain alive between query runs, and this might be useful with caching and optimization should you be writing a driver for an object database. Other than that, there shouldn't be any special considerations for object databases.
I have an application that will generate reports from various databases, each with the same schema. The only difference between DB1, DB2, DB3, and DBx is the data. All tables, views, etc are the same in structure.
For each participating DB in my application I have created a distinct Linq to SQL DataContext.
I am creating a ReportHelper class that will generate reports from the underlying data. I want to be able to call a Method like "GetCustomerSales" and have it spit back the data for my report. The problem is that I want to pass or set the DataContext for the GetCustomerSales method before I call it (ideally when constructing the ReportHelper Class).
However, my GetCustomerSales method wants me to use a specific DataContext, and I do not want to create this method over and over for each potential DataContext in use in the app. What's the correct approach here?
Have a single data-context, that matches the common schema. The difference is that instead of using just new SomeDataContext(), you should supply an appropriate connection-string (or connection) to the constructor:
var db = new SomeDataContext(connectionString);
or
var db = new SomeDataContext(connection);
Now all you need is multiple connection-strings, which is easier than multiple data-contexts. Two choices there; you can store multiple strings, perhaps in config (this is especially useful if they each need different user accounts etc); or - you can use SqlConnectionStringBuilder to create the connection string at runtime, specifying the appropriate database.
To illustrate; every site in the StackExchange network is ultimately a different database, but they all use the same data-context type. We simply tell it about the connection at runtime (based on which hostname you accessed).
You can get around it by passing a connection string to your data context.
public class DataRepository
{
private MyDataContext ctx;
public DataRepository(string connection){
ctx = new MyDataContext(connection);
}
//now you can use your context
}
I have an existing SQL Server database, where I store data from large specific log files (often 100 MB and more), one per database. After some analysis, the database is deleted again.
From the database, I have created both a Entity Framework Model and a DataSet Model via the Visual Studio designers. The DataSet is only for bulk importing data with SqlBulkCopy, after a quite complicated parsing process. All queries are then done using the Entity Framework Model, whose CreateQuery Method is exposed via an interface like this
public IQueryable<TTarget> GetResults<TTarget>() where TTarget : EntityObject, new()
{
return this.Context.CreateQuery<TTarget>(typeof(TTarget).Name);
}
Now, sometimes my files are very small and in such a case I would like to omit the import into the database, but just have a an in-memory representation of the data, accessible as Entities. The idea is to create the DataSet, but instead of bulk importing, to directly transfer it into an ObjectContext which is accessible via the interface.
Does this make sense?
Now here's what I have done for this conversion so far: I traverse all tables in the DataSet, convert the single rows into entities of the corresponding type and add them to instantiated object of my typed Entity context class, like so
MyEntities context = new MyEntities(); //create new in-memory context
///....
//get the item in the navigations table
MyDataSet.NavigationResultRow dataRow = ds.NavigationResult.First(); //here, a foreach would be necessary in a true-world scenario
NavigationResult entity = new NavigationResult
{
Direction = dataRow.Direction,
///...
NavigationResultID = dataRow.NavigationResultID
}; //convert to entities
context.AddToNavigationResult(entity); //add to entities
///....
A very tedious work, as I would need to create a converter for each of my entity type and iterate over each table in the DataSet I have. Beware, if I ever change my database model....
Also, I have found out, that I can only instantiate MyEntities, if I provide a valid connection string to a SQL Server database. Since I do not want to actually write to my fully fledged database each time, this hinders my intentions. I intend to have only some in-memory proxy database.
Can I do simpler? Is there some automated way of doing such a conversion, like generating an ObjectContext out of a DataSet object?
P.S: I have seen a few questions about unit testing that seem somewhat related, but not quite exact.
There are tools that map between objects, such as automapper. This is a very good open source tool.
However, these tools sometimes have problems, for example generating duplicate entity keys, or problems when the structure of the objects being mapped are very different.
If you are trying to automate it, I think that there is a greater chance of it working if you use EF 4 and POCO objects.
If you end up writing the mapping code manually, I would move it into a seperate procedure with automated unit tests on it.
The way we do this is to create a static class with "Map" methods":
From DTO to EF object
From EF to DTO
Then write a test for each method in which we check that the fields were mapped correctly.
We are using Linq to SQL to read and write our domain objects to a SQL Server database.
We are exposing a number of services (via WCF) to do various operations. Conecptually, the implementation of these operations consists of three steps: reconstitute the necessary domain objects from the database; execute the operation on the domain objects; persist the (now changed) domain objects back to the database.
Problem is that sometimes, there are two or more instances of the same entity objects, which can lead to inconsistenties when saving the objects back to the db. A little made-up example:
public void Move(string sourceLocationid, destinationLocationId, itemId);
which is supposed to move the item with the given id from the source to the destination location (actual services are more complicated, often involving many locations, items etc). Now, it could be that both source and destination location id are the same - a naive implementation would just reconstitute two instances of the entity object, which would lead to problems.
This issue is now "solved" by checking for it manually, i.e. we reconstitute a first location, check if the id of the second is different from it, and if so reconsistute the second, and so on. This is obvisouly difficult and error-prone.
Anyway, I was actually surprised that there does not seem to be a "standard" solution for this in domain driven design. In particular, repositories or factories do not seem to solve this problem (unless they maintain their own cache, which then needs to be updated etc).
My idea would be to make a DomainContext object per operation, which tracks and caches the domain objects used in that particular method. Instead of reconstituing and saving individual domain objects, such an object would be reconstituted and saved as a whole (possibly using repositories), and it could act as a cache for the domain objects used in that particular operation.
Anyway, it seems that this is a common problem, so how is this usually dealt with? What do you think of the idea above?
The DataContext in Linq-To-Sql supports the Identity Map concept out of the box and should be caching the objects you retrieve. The objects will only be different if you are not using the same DataContext for each GetById() operation.
Linq to Sql objects aren't really valid outside of the lifetime of the DataContext. You may find Rick Strahl's Linq to SQL DataContext Lifetime Management a good background read.
Also, the ORM is not responsible for logic in the domain. It's not going to disallow your example Move operation. That's up for the domain to decide what that means. Does it ignore it? or is it an error? It's your domain logic, and that needs to be implemented at the service boundary you are creating.
However, Linq-To-Sql does know when an object changes, and from what I've looked at, it won't record the change if you are re-assigning the same value. e.g. if Item.LocationID = 12, setting the locationID to 12 again won't trigger an update when SubmitChanges() is called.
Based on the example given, I'd be tempted to return early without ever loading an object if the source and destination are the same.
public void Move(string sourceLocationId, destinationLocationId, itemId)
{
if( sourceLocationId == destinationLocationId )
return;
using( DataContext ctx = new DataContext() )
{
Item item = ctx.Items.First( o => o.ItemID == itemId );
Location destination =
ctx.Locations.First( o => o.LocationID == destinationLocationID );
item.Location = destination;
ctx.SubmitChanges();
}
}
Another small point, which may or may not be applicable, is you should make your interfaces as chunky as possible. e.g. If you're typically going to perform 10 move operations at once, it's better to call 1 service method to perform all 10 operations at once, rather than 1 operation at a time. ref: chunky vs chatty
Many ORMs use two concepts that, if I understand you, address your issue. The first and most relevant is Context this is responsible for ensuring that only one object represents a entity (database table row, in the simple case) no mater how many times or ways it's requested from the database. The second is Unit of Work; this ensures that updates to the database for a group of entities either all succeed or all fail.
Both of these are implemented by the ORM I'm most familiar with (LLBLGen Pro), however I believe NHibernate and others also implement these concepts.