Is it possible to have multiple EDMX sharing the same model? - entity-framework

I need to have 2 different database (for example Oracle and SQLite) in a project.
I tried to use the same CSDL part for both EDMX, but then both generate the entity classes and I have compile error.
Is it possible to map to the same model?

You can't map to the same model because the model is generated by a code generator that handles one connection. I split my project into two, one for the application logic and one of project type "Class Library" (i.e. DLL) where I store the emdx. USing this method you can have access to multiple databases through different contexts, and and an added bonus, your code is more modular.

Related

Trying out Entity Framework Code-first; is the usage any different from Database-first?

When working with EF (v4,5,6) I have always used Database-first (I was mistakenly under the impression this was the only way to generate Entities from existing tables, EDMX, etc). But today I tryed Code-first, and it can also generate the POCOs (in a different way, no EDMX, different connection string, less cr8p lying around, etc..!)
So far, the usage of EF for CRUD appears to be exactly the same, can anyone who has used both please confirm there is nothing different (in usage), or gotchas I should be aware of?
And a supplementary question is, can I generate both in the same project ? (Not that i want to, but existing proj has EDMX within a folder, can I create another folder and generate Code-First Entities (different set of tables only), so i end up with DBContext and DBContext2 ?
Yes, the usage is the same. If you check the generated code you'll see they use the same System.Data.Entity.DbSet properties and they both inherit from the same System.Data.Entity.DbContext class.
Yes, you can generate both in the same project, but does not makes much sense, because you have to maintain both of them if the DB changes.

Reference existing CF project models

We have multiple model projects using codefluent (M1 and M2).
Is it possible to have one model project (say M1) using type reference of another model project (M2) ?
I tried adding project reference or existing item in model but none of them worked.
The import feature doesn't seem to be the way to go either
Shall I consider having only one model project for my solution ?
Thanks for your answer,
I think you want to create a relationship between entities of both models.
If so, it's easier to have only one model. If you create multiple models because of their sizes, you may be interested in parts and surfaces to split it (blog post about surfaces).
If you want to have multiple models, I think it's possible to create relationships between entities (but I didn't test it). You need to create the entity in both model and play with the producer specific attribute enabled (cfps:enabled, cfom:enabled, etc.). Unless you really want to do complex things, I think you may stick to one model.

Sharing entity types across multiple edmx files

We are using Entity Framework 4 with the POCO Entity Generator. Until now we've just had one .edmx file but we're running into performance problems due to the current size of it (well over 100 entities).
I understand we should be looking to break this into a series of .edmx files which is fine with one exception. We would want to somehow share certain entity types across two or more of these contexts. For example a User class is associated with numerous otherwise unrelated entities throughout our model.
So is it possible to have, say, a security model with its own .edmx and namespace for generated POCOs, but use it in another .emdx? If not I'm concerned we'll have multiple classes modelling the same database table which will need to be updated in sync with the database. I'd say that would be unworkable. (We're using database-first).
Obviously if I'm barking up the wrong tree do let me know!
In theory you can have single POCO class used with multiple EDMX mappings because the mapping and class must match only in the name and name/types of properties. In practice this has some limitations. Just few I can think about:
You cannot use automatic code generators with this approach unless you modify generator for every EDMX and make sure that every entity will be generated by just single generator from single EDMX. This directly points to second limitation.
Entity must be exactly same in every EDMX. Including navigation properties. If it is not you will not be able to generate it at all without building your own code generation solution. What is worse if dynamic proxies demand that class with unique name is mapped only once. If you have two or more different mappings for the same class you will not be able to use dynamic proxies (lazy loading, dynamic change tracking) with only single mapping per application run.

Is there a way of avoiding 2 repository objects for the same database table?

Im currently working in a team that uses EF as the ORM of choice.
We have a common project that contains many EDMX files.
The reason for this is to keep the EDMX files small and manageable while also allowing them to focus on a conceptual set of tables on the database.
Eg
Orders.edmx
Users.edmx
Trades.edmx
These all point to a different set of tables on the same db.
I now need to add the user table to the Trade.edmx file. Since the user table is already in the user.edmx file, this creates the same User type twice under a different namespace which means I would need 2 UserRepository objects.
Common.data.trade.User
Common.data.users.User
Is there a way of avoiding 2 repository objects for the same table?
Any suggestions would be greatly appreciated
If you are using POCO generator you can update template for Trades.edmx to not generate new User class and its context template to use User class from Users namespace. EF matches POCO classes with entities in designer only by the class name (namespace is omitted) so it will work.
The disadvantage is that you have User entity in two mapping files and you must update it in both files or your application throw exception at runtime.
The reason for this problem is your architecture - at the beginning you wanted separated models but know you want to combine entities from different models. Those are contradicting requirements. Either use separated model where Trade knows only userID without any navigation property (like if it is defined in another database) or move all entities to single EDMX to support your new requirements.

Compose queries across Entity Data Models

Is there a way to compose queries from 2 different entity models if the models are hitting the same underlying database.
The scenario I have is this:
I have a framework that uses EF for data access.(EDM 1)
I have a client application that uses services of the framework and also uses EF for it's own data access.(EDM2)
There are situations where I need to compose queries and join on entities that span the 2 EDMs.
Is there a way to do this without getting the data in memory from the first EDM and then apply additional predicates/joins in memory from the entities of the 2nd EDM?
I hope I'm articulating this the right way
EDIT
#Ladislav Mrnka:
The first EDM is the data access layer for a reusable framework.
It doesn't make sense to couple the EF generated entities from this EDM with
those of the consuming client
It defeats reusabilty of the API if I did this and I'd have to carry around additonal bloat
(EF metadata and DB tables of the client) everytime I wanted to redeploy the framework.
Also this would make managing the model in the designer unwieldy.
I'm currently using what you mention n item 7 as the solutuon and the performance is abysmal
due to the fact that I have to end up returning more data(i.e. entities) than needed from framework using
EDM1 and then filter out the ones not needed based on predicates/conditions based on value of
properties from entities in the second EDM. End result is a huge performance degradation and an unhappy DBA.
For this reason I ended up pushing the logic needed to retrieve the entities
to a SPROC in which I can access the tables that both EDMs use and apply the predicates needed
and have the entire query run in the DB as opposed to bringing the data in memory
and then filter out unnecessary ones.Downside is that I can't use LINQ
Item 8 that you mention sounds interesting but from what it sounds like I doubt that
you get strong typing at design time, or do you?
Can you upload your code sample someplace so that I can try it out?
Important edit
There is no build in support for achieving this with two ObjectContext types. Your query must always be executed against single ObjectContext.
Probably the best way to go: This was interesting enough for me to try it myself. I started with very simple idea. Two EDMX files (used with POCO T4 generators), each containing single entity. I take metadata description from second connection string and added it to first connection string. I used ObjectContext and ObjectSet directly. By doing this I was able to query and modify both entities from single ObjectContext instance. I also tryed to create query joining entities from both models and it worked.
This obviously works only if both EDMX map to the same database (same db connection string).
The important part is connections string:
<configuration>
<connectionStrings>
<add name="TestEntities" connectionString="metadata=res://*/FirstModel.csdl|res://*/FirstModel.ssdl|res://*/FirstModel.msl|res://*/SecondModel.csdl|res://*/SecondModel.ssdl|res://*/SecondModel.msl;provider=System.Data.SqlClient;provider connection string="Data Source=.;Initial Catalog=Test;Integrated Security=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>
This connection string contains metadata from two models - FirstModel.edmx and SecondModel.edmx.
Another problem is to force EF to use mapping from both these files. Each EDMX file must define unique container for SSDL and CSDL. ObjectContext offers property called DefaultContainerName. This property can be set directly or through some constructor overloads. Once you set this property you bind your ObjectContext instance to single EDMX - for this scenario you must not set this property. Omitting DefaultContainerName can have some consequences because some features and declarations can stop working (you will get runtime errors). You should not have problems with POCO unless you want to use some advanced features. You will most probably have proplems if you are using Entity objects (heavy EF entities. All methods using entity sets defined as strings are dependent on container. Due to this I suggest using such configuration only when necessary - for cross models queries.
Last problem is generating entities and "strongly typed" derived ObjectContext. The way to go is modify T4 template so that one template reads data from multiple EDMX files and generates context end entities for all of them - I already doing this in my project and it works. Default T4 implementation doesn't follow needed approach described in previous paragraph. Derived ObjectContext from default T4 implementation is dependent on single EDMX and entity container.
This part has been written before previous edit.
I'm leaving the rest of information just because some of them can be useful in other scenarios including work with multiple databases.
ORM like entity framework operates on top of mapping between object world and database world. In EF the object world is described by CSDL, database world is described as SSDL and mapping between them is described as MSL (all are just XML with well known schema). At design time these descriptions are part of model stored in EDMX file. During compilation these descriptions are extracted from EDMX and by default included as resource files to compiled assembly.
When you create instance of ObjectContext it receives connections string which contains reference to CSDL, SSDL and MSL resource files. SSDL or MSL do not specify include element to add information from other files. CSDL offers Using element which will allow you reusing existing mapping but this feature is not supported by designer. ConnectionString is used to initialize EntityConnection instance which is in turn used to initialize ObjectContext's MetadataWorkspace (runtime mapping information). Also ObjectContext doesn't provide any functionality of nesting multiple contexts into hiearchy. Connection string can't contain reference to multiple instances of these files. Edit: It can. I just tested it. See the initial paragraphs.
When you run Linq or ESQL query on the instance of ObjectContext it usese MSL to map your entities or POCO classes (defined by CSDL) into DB query (defined by SSDL description of database tables). If it doesn't have this information it will not work (and it can't have that information if it is stored in separate EDMX).
So how to solve this problem? There are several ways:
Always consider: Merge your mapping into one file (if multiple files are used for same database). That is supposed way to use EF and as you mentioned you are querying same DB so two EF models are not needed.
Duplicate entity description in second model. If you use EF4 and POCO you can map same descriptions from multiple models into one POCO class definition. I don't like this solution but sometimes it can help.
Define DB View or Stored procedure containing your query (or core of your query) and map it in one model to new entity.
Use DefiningQuery in one model (you will probably need 3rd one if you use Update from database feature) and map it to new entity. DefiningQuery is custom SQL query defined in SSDL instead of table or view description.
Use Function with custom CommandText specifying DB query. It is similar to using DefiningQuery and it has the same limitation. You must manually (in EDMX) map the result of the function into new complex type (another difference to DefiningQuery which is mapped to new entity).
Define new type for result of the query (properties of the type must have same names as returned columns in query) and use ObjectContext's ExecuteStoreQuery (only in EF4).
Divide query into two parts each executed separately on its own context and use linq-to-objects to get result. I don't like this solution.
This one is only high level idea - I didn't try it and I don't know if it works. As described above runtime mapping is dependent on the content of MetadataWorkspace instance which is filled from EntityConnection. EntityConnection also provides constructor which receives MetadataWorkspace instance directly. So generally if it would be possible to fill MetadataWorkspace from multiple EDMX you will not need multiple ObjectContext instances but your mapping would be still separated into two EDMXs. This would hopefully allow you writing custom Linq queries on top of two mapping files). Edit: It should be possible because it is exactly what EF is doing if you define multiple mappings in connection string.
Use CSDL Using feature for breaking the model into multiple reused parts.