New Posts New Posts RSS Feed: Minor problem using multiple Data Models with the same Entity Manager
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

Minor problem using multiple Data Models with the same Entity Manager

 Post Reply Post Reply
Author
Jonnic View Drop Down
Newbie
Newbie
Avatar

Joined: 15-Jul-2010
Posts: 2
Post Options Post Options   Quote Jonnic Quote  Post ReplyReply Direct Link To This Post Topic: Minor problem using multiple Data Models with the same Entity Manager
    Posted: 15-Jul-2010 at 8:23pm
Thank you, will try harder :)
Back to Top
ting View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 27-Mar-2009
Location: San Francisco
Posts: 427
Post Options Post Options   Quote ting Quote  Post ReplyReply Direct Link To This Post Posted: 15-Jul-2010 at 6:09pm
Actually, you're doing just fine.  However:
 
1)  You should be setting the "EntityManager Name" instead of the Entity Container Name.
 
2)  DevForce does not know how to generate the cross-datasource navigation automatically.  You have to write these properties manually.  If you're using WPF, this is fairly straightforward as it's just a LINQ query.  In Silverlight, it's a bit different because all non-cache queries have to be asynchronous, so we return pending collections or pending entities.  We don't have any examples of this yet, though.
 
 
Back to Top
Jonnic View Drop Down
Newbie
Newbie
Avatar

Joined: 15-Jul-2010
Posts: 2
Post Options Post Options   Quote Jonnic Quote  Post ReplyReply Direct Link To This Post Posted: 15-Jul-2010 at 4:05am
Hello!

Could you help me please?

I am using IdeaBlade 6.0.3.1 and VS 2010. I've tried to make a model that uses 2 different data sources, and i can't figure how to do this. So, i have two databases and i need to build a single datamodel that includes data form both DBs and a navigation links between them.

My steps was:
0) the TestAssembly was created
1) the first model (model1.edmx) was created, and it's Entity Container Name was set to, say, "MyContainer".
2) the second model (model2.edmx) was created from the another DB, and it's Entity Container Name was set to "MyContainer" too.
3) the TestAssembly was complied, and i've got an TestAssembly.MyContainer class that contains entities from the both DBs. But i can't fugure out how to create navigation links and associations between the model1.edmx and model2.edmx.

Am i right doing that?

Can you point me to some step-by-step instruction (for stupid idiots like i am)?

Sorry for my english :(
Back to Top
DavidKozikowski View Drop Down
Groupie
Groupie
Avatar

Joined: 02-Feb-2010
Location: Aurora, IN
Posts: 59
Post Options Post Options   Quote DavidKozikowski Quote  Post ReplyReply Direct Link To This Post Posted: 11-Jun-2010 at 4:30am
Greg,
Thanks for the explanation. That's exactly the kind of information I was looking for!
Back to Top
GregD View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 09-May-2007
Posts: 374
Post Options Post Options   Quote GregD Quote  Post ReplyReply Direct Link To This Post Posted: 10-Jun-2010 at 12:59pm

Originally posted by DavidKozikowski

 
<span style="font-family: 'Verdana','sans-serif'; color: black; font-size: 13.5pt;" lang="EN">Perfect!What is the difference / purpose of the Default Manager then? Why use it over the creation of a “new” one? </span>
Well, actually...You can accommodate multiple EDMX models within a single DevForce domain manager, which is possibly what you really want to do. To do that:
  1. Open the first EDMX in designer view, and in the Properties pane set the EntityManager Name property to whatever you'd like the common EntityManager to be called -- let's say "DomainModelManager". Save the model; DevForce will generate code.
  2. Open the second EDMX in designer view, and set its EntityManager Name to the same thing. Save and generate.
You can see in the generated code that the specialized EntityManagers are generated as partial classes: now they'll be partials of the same class.  Your new DefaultManager will include entities from both of the EDMX models.To return to your question: EntityManager is a singleton, so the first instance created (whatever specialized subtype of EntityManager it also is) is the one subsequently returned by the EntityManager.DefaultManager property. If there is no existing instance when the DefaultManager property is referenced, an instance is created and it becomes the one returned by all subsequent references to DefaultManager.The idea of DefaultManager is to make it easy for all parts of your application to use the same EntityManager, if that's what you to do. If you initialize EntityManager variables to MyEntityManager.DefaultManager throughout your app, you always get the same instance. If you ever want a separate instance, you can new() it - just remember that if you have NOT already initialized DefaultManager, the instance you new() up will become that.

Edited by GregD - 11-Jun-2010 at 2:39pm
Back to Top
DavidKozikowski View Drop Down
Groupie
Groupie
Avatar

Joined: 02-Feb-2010
Location: Aurora, IN
Posts: 59
Post Options Post Options   Quote DavidKozikowski Quote  Post ReplyReply Direct Link To This Post Posted: 10-Jun-2010 at 4:51am
Originally posted by GregD

David:

DefaultManager is a static property of the EntityManager class, which both _GTDMEntityManager and _PTXARCEntityManager inherit. Thus you are simply accessing a single property through your two initialization statements in the Private Fields region. Once both statements have executed, the EntityManager.DefaultManager property points to an instance of _GTDMEntityManager, since that was the first one created.

Use this instead:

static GTDMEntityManager _GTDMEntityManager = new GTDMEntityManager();
static PTXARCEntityManager _PTXARCEntityManager = new PTXARCEntityManager()


If you need to keep up with a default instance of each EM subtype, you'll need to create your own static properties; or at least one static property, anyway.
 
 
Perfect!
What is the difference / purpose of the Default Manager then? Why use it over the creation of a “new” one? I have been using the samples as starting points but I think I need to understand the thinking behind these 2 ways of using the entity manager.
 
Thanks!
Back to Top
GregD View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 09-May-2007
Posts: 374
Post Options Post Options   Quote GregD Quote  Post ReplyReply Direct Link To This Post Posted: 09-Jun-2010 at 4:42pm
David:

DefaultManager is a static property of the EntityManager class, which both _GTDMEntityManager and _PTXARCEntityManager inherit. Thus you are simply accessing a single property through your two initialization statements in the Private Fields region. Once both statements have executed, the EntityManager.DefaultManager property points to an instance of _GTDMEntityManager, since that was the first one created.

Use this instead:

static GTDMEntityManager _GTDMEntityManager = new GTDMEntityManager();
static PTXARCEntityManager _PTXARCEntityManager = new PTXARCEntityManager()


If you need to keep up with a default instance of each EM subtype, you'll need to create your own static properties; or at least one static property, anyway.
Back to Top
DavidKozikowski View Drop Down
Groupie
Groupie
Avatar

Joined: 02-Feb-2010
Location: Aurora, IN
Posts: 59
Post Options Post Options   Quote DavidKozikowski Quote  Post ReplyReply Direct Link To This Post Posted: 09-Jun-2010 at 11:45am

I get errors when I try to do something like the below code.
It only allows "one default" manager Should I set the Entitity Manager names to be the same on each edmx?
 
 
private void Temp2_Load(object sender, EventArgs e)

{

_SystemComponent.ReplaceRange(_PTXARCEntityManager.SystemComponents.ToList());

bindingSource1.DataSource = _SystemComponent;

_GTDM_AUTHENTICATION.ReplaceRange(_GTDMEntityManager.GTDM_AUTHENTICATION.ToList());

bindingSource2.DataSource = _GTDM_AUTHENTICATION;

}

#region Private Fields

static GTDMEntityManager _GTDMEntityManager = GTDMEntityManager.DefaultManager;

IdeaBlade.Util.BindableList<GTDM_AUTHENTICATION> _GTDM_AUTHENTICATION = new IdeaBlade.Util.BindableList<GTDM_AUTHENTICATION>();

static PTXARCEntityManager _PTXARCEntityManager = PTXARCEntityManager.DefaultManager;

IdeaBlade.Util.BindableList<SystemComponent> _SystemComponent = new IdeaBlade.Util.BindableList<SystemComponent>();

#endregion

Back to Top
pk55 View Drop Down
Senior Member
Senior Member


Joined: 22-Jul-2009
Location: CA
Posts: 105
Post Options Post Options   Quote pk55 Quote  Post ReplyReply Direct Link To This Post Posted: 26-Apr-2010 at 5:23pm
That doesn't work, which was the whole point of the post.  With 6 models, I tried everything and it still thought 2 of them were primary.  I had to force setting IsPrimaryEdmx to true for one model and false for the others.
 
I also (just an FYI) had to override the WriteStandardHeader method since it was the other place that referenced this value (for including the IB license info in the primary model).
Back to Top
ting View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 27-Mar-2009
Location: San Francisco
Posts: 427
Post Options Post Options   Quote ting Quote  Post ReplyReply Direct Link To This Post Posted: 26-Apr-2010 at 5:05pm
Hi Guys,
 
Thanks for pointing this out.  We do have logic that manages the "primary" and "secondary" managers, but the eventing code path when a new model is added has a bug.  We will get this fixed.
 
Here are the simplest rules I've found when fixing an issue with multiple EDMXs:
  1. Name the EntityManagers all to their desired names.
  2. Right click on each .tt, and select 'Run Custom Tool'.
This invokes the DevForce logic which will get the primary and seconday classes synchronized.
 
Back to Top
pk55 View Drop Down
Senior Member
Senior Member


Joined: 22-Jul-2009
Location: CA
Posts: 105
Post Options Post Options   Quote pk55 Quote  Post ReplyReply Direct Link To This Post Posted: 26-Apr-2010 at 2:14pm
Just noticed your CsdlWrapper has this exact bool, IsPrimaryEdmx, which you use to decide if you should run the ctors/creation, so if you could just expose that in the edmx DevForce properties, life would be good. 
 
I ended up just overriding this bool in 5 of the 6 models T4 (all of their T4 templates now just include a common T4 so the code isn't repeated) and in one of them, I force it to be the primary.  This way, I don't have to have a separate class for the Entity Manager ctors/creation and I can just let your code do it's stuff and I always know which one has the EM created.
Back to Top
pk55 View Drop Down
Senior Member
Senior Member


Joined: 22-Jul-2009
Location: CA
Posts: 105
Post Options Post Options   Quote pk55 Quote  Post ReplyReply Direct Link To This Post Posted: 26-Apr-2010 at 11:35am
One last thought about a fix for this;  I'd vote for a boolean property, "Create Entity Manager in this EDMX?" on the DevForce section of the edmx that defaults to True (for those with just one model).  For those with multiple models, we can pick which edmx should have the EM ctors/creation or if we want to override the ctors/creation with a separate class like I did with the T4, then we can set all of them to False.
 
Back to Top
pk55 View Drop Down
Senior Member
Senior Member


Joined: 22-Jul-2009
Location: CA
Posts: 105
Post Options Post Options   Quote pk55 Quote  Post ReplyReply Direct Link To This Post Posted: 26-Apr-2010 at 11:19am
I've got another work-around to run by IB.  In the T4 template for each model, I'm overriding the entity manager ctors and default manager creation which means I have a separate class (linked to the Silverlight project of course) that does the ctors and creation once. 
 
It's a hack but until IB releases a fix, but this will get around the duplicate declarations.
 
Change the <modelname>.edmx.tt file that is auto-created for each *.edmx to (either plugging in your data model name where it says $edmxname$: 
 
<#@ template  language="C#" debug="true" hostSpecific="true" #>
<#@ output extension=".ReadMe" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ Assembly Name="System.Data.Entity.dll" #>
<#@ Assembly Name="Microsoft.VisualStudio.TextTemplating.10.0" #>
<#@ Assembly Name="IdeaBlade.Core" #>
<#@ Assembly Name="IdeaBlade.VisualStudio.DTE.dll" #>
<#@ Assembly Name="IdeaBlade.VisualStudio.OM.CodeGenerator.dll" #>
<#@ Assembly Name="IdeaBlade.EntityModel.Edm.Metadata.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Data.Entity" #>
<#@ import namespace="IdeaBlade.VisualStudio.DTE" #>
<#@ import namespace="IdeaBlade.VisualStudio.OM.CodeGenerator" #>
<#@ import namespace="IdeaBlade.EntityModel.Edm.Metadata" #>
<#
 // Source for this file located at: $templateFullFileName$
 // $edmxname$  <--- This is needed so that "Transform Related Text Templates On Save" works correctly.
 var template = new MyTemplate(this);
 template.Generate();
#>
<#+
 public class MyTemplate : DomainModelTemplate {
  public MyTemplate(Microsoft.VisualStudio.TextTemplating.TextTransformation textTransformation)
   :base(textTransformation) {}
    
   // HACK: override to prevent DevForce from generating the EM in the designer files
   // since it seems to get confused by multiple EDMX files using the same EM.
   // This means we have to have a partial class for the default em declared that does
   // the constructor/new-up of the EM and link that class in the Silverlight project
   protected override void WriteEntityManagerCtors(CsdlWrapper csdl)
   {
    WriteToOutputWindow("Suppressing Entity Manager Constructor Generation for: " +
     csdl.EntityManagerName);
   }
   
   protected override void WriteEntityManagerDefaultManager(CsdlWrapper csdl)
   {
    WriteToOutputWindow("Suppressing Entity Manager Default Manager Generation: " +
     csdl.EntityManagerName);
   }
   
 }
#>
 
Adding a partial class for the Domain Model Entity Manager (the common EM shared across data models) and linking this class to the Silverlight project.  For example:
 
MyEntityManager.cs (just copied the stuff from the *.IB.Designer.cs file):
 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.Serialization;
using IbEm   = IdeaBlade.EntityModel;
using IbCore = IdeaBlade.Core;
using IbVal  = IdeaBlade.Validation;
 
namespace <yournamespacehere>
{
    /// <summary>
    /// The domain-specific EntityManager for your domain model.
    /// </summary>
    public partial class MyEntityManager : IbEm.EntityManager
    {
        #region Constructors
        /// <summary>See <see cref="M:IbEm.EntityManager.#ctor()"/>. </summary>
        public MyEntityManager() : base() { }
        /// <summary>See <see cref="M:IbEm.EntityManager.#ctor(Boolean)"/>. </summary>
        public MyEntityManager(Boolean shouldConnect) : base(shouldConnect) { }
        /// <summary>See <see cref="M:IbEm.EntityManager.#ctor(Boolean, String)"/>. </summary>
        public MyEntityManager(Boolean shouldConnect, String dataSourceExtension) : base(shouldConnect, dataSourceExtension) { }
        /// <summary>See <see cref="M:IbEm.EntityManager.#ctor(Boolean, String, IbEm.EntityServiceOption)"/>. </summary>
        public MyEntityManager(Boolean shouldConnect, String dataSourceExtension, IbEm.EntityServiceOption entityServiceOption) : base(shouldConnect, dataSourceExtension, entityServiceOption) { }
        /// <summary>See <see cref="M:IbEm.EntityManager.#ctor(IbEm.EntityManager)"/>. </summary>
        public MyEntityManager(IbEm.EntityManager entityManager) : base(entityManager) { }
        /// <summary>See <see cref="M:IbEm.EntityManager.#ctor(IbEm.EntityManager, Boolean, String, IbEm.EntityServiceOption)"/>. </summary>
        public MyEntityManager(IbEm.EntityManager entityManager, Boolean shouldConnect, String dataSourceExtension, IbEm.EntityServiceOption entityServiceOption) : base(entityManager, shouldConnect, dataSourceExtension, entityServiceOption) { }
        static MyEntityManager()
        {
            IbEm.EntityRelation.InitializeEntityRelations(Assembly.GetExecutingAssembly());
        }
        #endregion Constructors
        #region DefaultManager
        /// <summary>Gets the default manager. </summary>
        public new static MyEntityManager DefaultManager
        {
            get { return GetDefaultEntityManager<MyEntityManager>(); }
        }
        #endregion DefaultManager
    }
 
Back to Top
pk55 View Drop Down
Senior Member
Senior Member


Joined: 22-Jul-2009
Location: CA
Posts: 105
Post Options Post Options   Quote pk55 Quote  Post ReplyReply Direct Link To This Post Posted: 26-Apr-2010 at 7:42am
This may not be as 'minor' a bug as I originally thought.  With just two models, I'm able to use the work-around but with six models, I can't seem to get just one of them to create the Entity Manager.  It consistently is creating the EM in 2 of the 6 models; the other four just declare a partial class for it. 
 
Can someone from IdeaBlade weigh in on this, maybe with a better work-around or a fix?
 
Back to Top
smi-mark View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 24-Feb-2009
Location: Dallas, Texas
Posts: 343
Post Options Post Options   Quote smi-mark Quote  Post ReplyReply Direct Link To This Post Posted: 23-Apr-2010 at 3:34pm
Interesting. I had the same issue when I tried it - figured I was doing something wrong. Thanks for the workaround!
Back to Top
pk55 View Drop Down
Senior Member
Senior Member


Joined: 22-Jul-2009
Location: CA
Posts: 105
Post Options Post Options   Quote pk55 Quote  Post ReplyReply Direct Link To This Post Posted: 23-Apr-2010 at 7:55am
I was trying to create a second data model to combine with another model into a common Domain Data Model using the DF2010 method of specifying the same EntityManager name for each model in the edmx properties and in theory, the code gen will only create the constructors/default entity manager once and they'll be treated as a common model.
 
I had the first model already created and didn't edit or open it prior to adding the second model.
 
I created the second model, setting it's EntityManager name to the same one used by the first model and saved.  Code gen worked but when I built the solution, I get errors as the second model generated code tries to instantiate the same EM constructors and new-up the same default entity manager.
 
If, however, I edit both edmx files and change their EntityManager name to a different common name and save all together (can't save each change or you have the same problem), it works fine.   The first code gen file does the constructors/new-up EM and the second skips it.
 
So any time a new model is added (obviously not that often), I need to have all the models checked out and change all of them together (presumably to a new name and then back to the real EM name) before building the solution or is there something I'm missing?
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down