none
EDM Designer's Annoying "We'll do it for you" BS

    Question

  • I just started working with .NET 3.5 and VS2008 SP1 in a production capacity today. We are building an entity model from a database with hundreds of tables, and I've come accross a MASSIVE annoyance that I am hoping has a "permanently turn it off" switch somewhere. We want our entity sets to have plural names, and the entities to have singular names. For some reason, not exactly sure why, the EDM designer automatically generates entities with the same set and entity name, and its always plural. So, for example, we get the Products entity set with Products entities in it...thats just dumb. So, I started renaming all of our entities to singular...figured, eh, it will only take a while once, then its done. Well, I renambed a bunch of entities, and suddenly noticed that whenever I change an entity from singular to plural, the designer, in that OH SO SO VERY VERY ANNOYING MICROSOFT FASION, decided to change the set name too!! So now, I have hundreds of entities with singular names, but with the wrong set name: ProductSet entity set with Product entities in it. I now have to go back and CHANGE EVERYTHING AGAIN to get my entity set names back to what they were originally, which was exactly what I wanted, but which the EDM designer decided to SCREW WITH behing my back without telling me it was doing so, OR giving me the option to NOT DO IT. 

    This is a serious problem with Microsoft products, and Microsoft needs to STOP DOING IT. We don't want you to automatically decide whats best for us, because you have no clue what we want. Your great at providing flexible frameworks, but your tools become intensely inflexible in practical situations because they impose so many limitations or automaitc "we'll fix it for you" ***. I seriously hope there is some way to turn off this "Feature", because if I have to constantly fight the designer to keep correct naming, I'm going to be an extremely unhappy programmer who might end up jumping the EF ship for something less....annoying. -.-

    Monday, August 18, 2008 6:43 PM

Answers

All replies

  • jrista,

     

     You are totally correct - this is not the right behavior. We will file a bug and fix this. For now, once you fix the entityset name again, the designer will not mess with it again.

     

     I'd also like to note that we are working on a pluralization/depluralization feature and trying to fit it into the next release.

     

    Thank you,

      Noam

     

    Monday, August 18, 2008 7:55 PM
    Moderator
  • Alright, good to know the names won't change again. And I greatly look forward to the pluralization/depluralization...that will make my day.
    Monday, August 18, 2008 8:06 PM
  • Or you can generate your edmx  rather letting EF do it for you.

    Monday, August 18, 2008 8:23 PM
  • "For now, once you fix the entityset name again, the designer will not mess with it again."

    I just noticed that statement doesn't seem to hold true...I've changed entity names on a few entities more than once, and each time I change the name, the set name changes to the entity name + "Set", even after I've edited the set name manually.

    Generating our entity model isn't really viable because I am creating logical entities that work for code that do not directly map 1-1 to our tables in the database. For example, we have a fully normalized Addresses table wich contains all addresses, which are linked to other tables through join tables with payloads. When working with LINQ to SQL, dealing with this scenario was a really pain. The approach were taking now with EF is more like the following:

    Tables
    ========
    PhoneNumbers
    Addresses
    Companies
    CompaniesAddressesJoin (Contains IsPrimary payload)
    CompaniesPhoneNumbersJoin (Contains IsPrimary and PhoneNumberType payload)

    Entities
    ========
    Company
    CompanyAddress (Merges Addresses and CompaniesAddressesJoin fragments)
    CompanyPhoneNumber (Merges PhoneNumbers and CompaniesPhoneNumbersJoin fragments)

    The CompanyAddress and CompanyPhoneNumber entities use stored procs behind the scenes to perform CUD ops.

    The logical entity model should greatly simplify a lot of the LINQ to SQL code we have and make utilizing our Domain much easier, at the initial cost of building the EDM. Sadly I think any fixes to EDM designer bugs will come too late for us to benefit from them.
    Monday, August 18, 2008 9:00 PM
  • That's interesting - I've not been able to reproduce that behavior: Once I change the set name, the designer no longer touches it.

     

    For now, I know this is somewhat lame, but what about just changing the names directly in the XML? Alternatively, using Kristof's tool could also work well - it looks like a nice piece of work.

     

    Monday, August 18, 2008 9:10 PM
    Moderator
  • Here are a few more quirky annoyances with the EDM designer:

    1) Updating from the database after deleting an association will add the association back to the conceptual model.
    2) Deleting an entity that is associated to one or more other entities will leave the associations in the conceptual model...then there is no way to delete the associations without editing the xml.

    3) Deleting a normalized entity (i.e. Addresses, related to say Companies and Contacts through the use of join tables for an *-* relationship), then creating other entities from fragments of the join table and the normalized table, will cause associations added back during an update from the database to be related to the entities made from fragments of the normalized table.

    An example of the third issue:

    Tables
    ==========
    Addresses
    Companies
    CompaniesAddressesJoin
    Contacts (has an AddressID for a direct join)

    Entities
    ==========
    Company
    CompanyAddress (fragments, merges CompaniesAddressesJoin with Addresses)
    Contact

    The CompanyAddress entity is built from Addresses and CompaniesAddressesJoin. I am having other problems getting this entity to work properly (I'll be posting another thread to discuss that), but it has a CompanyID and AddressID as the entity key. Whenever I update my model from the database, any associations from other entities (line Contact, which has an AddressID in the database) to the Addresses table (that were previously deleted, along with the Addresses entity) are added back, but now point to the CompanyAddress table. The CompanyAddress table has no direct mapping to the database....so I am assuming the only reason the associations that are added back (which should not be...I don't want them there at all) are being associated with this entity is because its the only other entity with an AddressID property on it. Whatever the specific cause is...the update from database function is not only adding associations back that I am trying to delete, but its adding associations back and linking them to entities that they should never ever be linked with in the first plade...its like its picking the first entity that they could possibly be associated with (because the actual entity they would associate with, Address, has also been removed from the model), and linking them to it.

    Now, I'm sure I could find ways of solving these problems by editing the EDM xml directly...but that is defeating a significant part of the reason we decided to move to EF in the first place...the expected (and now apparently assumed) simplicity and ease with which we could manage and maintain our conceptual model using a visual designer. From all appearances, and some muddling with Beta 1, it seemed that EF would allow us to overcome some of the inherant problems with LINQ to SQL. Simple example scenarios seemed to work in Beta 1, with occasional validation errors that didn't actually cause any problems when the conceptual model was queried. In particular, dealing with many to many associations with payload between a fully normalized table and a parent (Companies have CompanyAddresses from a conceptual standpoint....not CompanyAddressJoins which in turn have an Address). Since our foray into using EF in a practical scenario with an existing, populated, and properly normalized database, the convenience of using EF has largely vanished, exposing an unending wall of limitations, annoyances, and incompatabilities that has effectively ended our current attempt move from LINQ to SQL to EF (or, use EF the same way we use LINQ to SQL...1-1 table to entity mappings and not really gain anything new...like entities constructed from table fragments).

    I'm sadly dissapointed with how EF v1.0 has turned out, and I really hope that v2.0 will arrive quickly and mitigate, or preferably, eliminate the current limitations imposed by model restrictions and visual designer quirks (in addition to the already well-known need for POCO, Unit Testability, etc.)
    Tuesday, August 19, 2008 12:03 AM
  • Thank you for the feedback. The update model from database feature is linking those entities together because it is seeing foreign key constraints between the tables that the types are mapped to. I'm surprised that you find this behavior surprising: You have a foreign key constraint in your SSDL, and the model needs some way to obey that constraint. It is not the case that "the CompanyAddress has no direct mapping to the database." It is, as you say, mapped directly to the Addresses and CompaniesAddressesJoin. And the foreign keys in your database means that the Contacts table doesn't come into the model with the AddressID property in it, but rather with a relationship to any type mapped to the address table.

     

    So, I appreciate your frustration, but I don't see a straightforward of changing this behavior without significant surgery to the wizard and components below it. (e.g. To make the system ignore specific foreign key constraints.)

     

    As for deleting an entity leaving the association behind, I have not been able to replicate this behavior. Note that we will remove CSDL associations, but not SSDL associations. If you want to remove those associations, you'll need to either do it by hand and avoid using the update model from database feature, or remove them from the database, or use views for read and stored procedures for update. I wish I had a better answer there, but there you are.

     

    Given our current plans, and for the specific complaints above, I do not expect that your specific issues will be fully resolved in v2. We'll definitely try to take care of the set renaming issue, but some of your other complaints are probably going to be with us for a while as we focus on major product gaps. There is a lot of work that we want to do on the update model from database feature, but however much of it we do, if any, I don't see it making your specific issues much better in the near future. (Disclaimer: This is just my own assessment of the situation.)

     

    Respectfully,

      Noam

    Tuesday, August 19, 2008 12:56 AM
    Moderator
  • "And the foreign keys in your database means that the Contacts table doesn't come into the model with the AddressID property in it, but rather with a relationship to any type mapped to the address table."

     

    I'm a little confused by that statement, particularly the "any type" part. My foreign key in the database is quite explicit, and specifically maps between Contacts and Addresses. There is little ambiguity about the foreign key, so I don't understand why there would be any ambiguity or randomness about what entities the association points to in the conceptual model. I would not be surprised if the Address entity was added back and the association pointed to that, nor would I be surprised if the association was not added back at all. However, I am surprised that the association automatically points to the CompanyAddress entity simply because its the only thing that maps to the Addresses table.

     

    I am also surprised that every foreign key in the database must have an association in the conceptual model, even if its an invalid association? For the time being I have scaled back our entity model and am trying to keep it simple, so I removed a bunch of entities and associations that we will not need to use in the short term. I can keep deleting the associations every time we update, and the model works fine (if I remove other things that are causing problems), so I don't understand why the update from database wizard insists on adding them back.

    Tuesday, August 19, 2008 1:20 AM
  • Sorry, that was sloppy phrasing. The key point is that there can be multiple types mapped to the same table, e.g. in the case of TPH mapping. In practice, this is the root of the object inheritance hierarchy.

     

    I am surprised that you can delete the association and have the model still validate but I am not an expert on that part of the system. It sounds like we need an option in the wizard to "resurrect deleted associations."

    Tuesday, August 19, 2008 2:01 AM
    Moderator
  • Noam,

     

    A suggestion for the update/sync command: allow the user to specify (and store) preferences - including tables, columns, and FKs to ignore on the database side, and entitysets, entitytypes, and properties to ignore on the csdl side.

     

    In my dbml resync add-in I store that kind of preferences in a separate file (MyDataContext.dbml.prefs) so subsequent updates are aware of what differences to ignore during resync. Here's an example of a .dbml.prefs:

     

    <?xml version="1.0"?>
    <SyncPreferences xmlns:xsi="
    http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <SavePreferences>true</SavePreferences>
      <NewTables>true</NewTables>
      <DroppedTables>true</DroppedTables>
      <NewColumns>true</NewColumns>
      <DroppedColumns>true</DroppedColumns>
      <ModifiedColumns>true</ModifiedColumns>
      <PrimaryKeyChanges>true</PrimaryKeyChanges>
      <NewForeignKeys>true</NewForeignKeys>
      <DroppedForeignKeys>true</DroppedForeignKeys>
      <IgnoreTables>

        <string>dbo.sysdiagrams</string>

      <IgnoreTables>

      <IgnoreColumns />
      <IgnoreFKs />
      <IgnoreTypes />
      <IgnoreMembers />
      <IgnoreAssociations />
    </SyncPreferences>

     

     

    In EDMX you can even embed those preferences in the file (the reason for a separate file in dbml is that the dbml designer doesn't like non-dbml data embedded in the file and throws it away). Structured annotations [or a custom section if allowed - I haven't tried that yet] can be used in the edmx.

     

    For the naming - same thing, allow the users to specify and store their preferences and then the update command and editor can follow those preferences. Here's an example of the naming preference file that I use in my name update add-in for edmx:

     

    <?xml version="1.0"?>
    <NamePreferences xmlns:xsi="
    http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <EntitySetPrefs>
        <ProperCase>true</ProperCase>
        <RemoveUnderscore>true</RemoveUnderscore>
        <RemovePrefixes>
          <string>tbl</string>
          <string>tb</string>
        </RemovePrefixes>
        <RemoveSuffixes>
          <string />
        </RemoveSuffixes>
        <AddPrefix />
        <AddSuffix />
        <Pluralize>true</Pluralize>
      </EntitySetPrefs>
      <EntityTypePrefs>
        <ProperCase>true</ProperCase>
        <RemoveUnderscore>true</RemoveUnderscore>
        <RemovePrefixes>
          <string />
        </RemovePrefixes>
        <RemoveSuffixes>
          <string />
        </RemoveSuffixes>
        <AddPrefix />
        <AddSuffix />
        <Pluralize>false</Pluralize>
      </EntityTypePrefs>
      <PropertyPrefs>
        <ProperCase>true</ProperCase>
        <RemoveUnderscore>true</RemoveUnderscore>
        <RemovePrefixes>
          <string />
        </RemovePrefixes>
        <RemoveSuffixes>
          <string />
        </RemoveSuffixes>
        <AddPrefix />
        <AddSuffix />
        <Pluralize>false</Pluralize>
      </PropertyPrefs>
      <SavePreferences>true</SavePreferences>
    </NamePreferences>

    Tuesday, August 19, 2008 2:22 AM
  • Thank you Kris, We agree that these settings should be persistent and set up per edmx file. Being able to exclude objects such as columns and foreign keys makes sense. Don't know how much we'll get done, but we'll capture all of this for our work item lists.

     

    Thank you!

     Noam

    Tuesday, August 19, 2008 2:27 AM
    Moderator
  • I have encountered another quirk with the EDM designer. If I create a new association, and type in a name, then choose the tables, my custom name is automatically overwritten with an autogenerated name. It took a few custom associations to figure out what was happening, but if a custom name is typed in before selection of the tables in the create association dialog, it should stick, and should not be overwritten by any autogenerated name.

    Tuesday, August 19, 2008 6:48 PM
  • jrista,

     

     I have not been able to reproduce this behavior. Would you be willing to provide a step-by-step repro?

     

    Tuesday, August 19, 2008 8:13 PM
    Moderator
  • [Assuming 4 existing entities: Company, CompanyAddressesJoin, Address, CompanyAddress]

    1) Right-click blank design surface.
    2) Choose Add -> Association...
    3) Type in a name for the association (i.e. FK_Company_CompanyAddress)
    4) Select the first end (i.e. Company)
    *** Here is the first automatic change...my association name is now "CompanyCompany"
    5) Select the second end (i.e. CompanyAddress)
    *** Here is the second automatic change...my association name is now "CompanyCompanyAddress"

    Selecting the tables for the association ends automatically changes the name for the association, even if the name was manually entered.




    Another issue, not sure if this is a bug, or currently expected behavior. I have been trying to solve problems creating entities that merge CompaniesAddressesJoin and Addresses into a CompanyAddress entity. I gave up tryign to get it done purely with EF, and created a backing view. The backing view is a simple inner join, with schemabinding, and has a unique clustered index on the CompanyID and AddressID columns. Updating the database model and adding this view causes it to be added with four columns marked as the entity key: CompanyID (int), AddressID (int), IsPrimary (bit), CreateDate (datetime). The entity key should be just CompanyID and AddressID...does the visual designer not check indexes on views to determine the entity key? If not, is there some way to edit this in the visual designer (currently, all table information is locked in the model tree, and can not be edited).

    I can edit the xml manually, but then I have a problem where, next time I update from the database and close the .edmx file, I can no longer open it with the visual designer. Double-clicking the file just expands it in the solution explorer (showing the .Designer.cs file), and right-clicking then choosing Open With -> ADO.NET Entity Data Model Designer (Default) does nothing. I can still open it with the XML Editor, just not the designer. It takes closing and reopening Visual Studio to be able to edit again.


    Tuesday, August 19, 2008 9:06 PM
  • The CompanyAddress table has no direct mapping to the database....so I am assuming the only reason the associations that are added back (which should not be...I don't want them there at all) are being associated with this entity is because its the only other entity with an AddressID property on it. Whatever the specific cause is...the update from database function is not only adding associations back that I am trying to delete, but its adding associations back and linking them to entities that they should never ever be linked with in the first plade...its like its picking the first entity that they could possibly be associated with (because the actual entity they would associate with, Address, has also been removed from the model), and linking them to it.

    I don't really see how you would make this work at all, because Contact now has an FK field you'll never be able to set to a value, as there's no Address entity in your model so you'll never be able to save a new Contact: it needs a relationship with Address, unless you've mapped Contact on the tables Contact and Address, which to me would make absolutely no sense at all, as Address is actually a value type (DDD) without identity, OR, a full blown entity WITH identity (which is the case in your table model).

    Keep in mind that your tables probably were designed like this because they're the projection result of an abstract entity model (think NIAM/ORM level). While it might make some sense in code to de-normalize a bit in code outside the database, in practise it could lead to many problems, based on the fact that there's a difference between what a 'Contact' means (if it is mapped on two tables Contact and Address) in code and what it means in a row in the relational model
    Wednesday, August 20, 2008 5:09 PM
  • I'm sorry, I still cannot reproduce what you are seeing. How, exactly, are you selecting the association ends? Are you expanding the End properties in the association property sheet? I tried that and that didn't do it. Are you selecting the navigation properties? If so, are you sure you aren't simply seeing the navigation property name in the property sheet?

     

    To answer your question, the designer does not check indexes on the view - that isn't typically a workable strategy anyway. For views, the logic will simply look for all non-nullable fields, if I recall, and make them part of the key.

     

    You are correct that for the S-Side we cannot yet provide editing capabilities. Your best bet if you want to change the key definition is to either do it in the SSDL (and as you say risk losing the change when you update the model from the database,) or make IsPrimary and CreateDate nullable, which I believe removes them from the primary key inference system's candidates list.

     

    We would like to implement an SSDL merge capability so that the update wizard does not muck with your changes, we're pushing that feature hard to see if we can deliver on it, but cannot be sure that it will fit in the next release. We appreciate posts like this as they help us to gauge the importance of doing this work.

     

    HTH,

      Noam

    Wednesday, August 20, 2008 5:37 PM
    Moderator
  • I am creating a brand new association, from scratch, in the EDM designer. It initially has no table mapping in the database, I add that after it is created. To create the association, create a new .edmx file from a database. Once the model is created, do the following to create the assocation (You should have 4 entityes if you use the schema below: Companies, CompaniesAddressesJoin, Addresses, CompanyAddresses):

    1) Rename each entity Name to be non plural (you should encounter the EntitySet renaming bug when you do this).
    2) Right-click a BLANK spot on the model (don't right click an entity or an association).
    3) Choose Add->Association...
    4) The Add Association dialog appears with the following info by default:
    - Association Name = AddressCompany (it just defaults to this)
    - Left End Entity Dropdown = Address
    - Left End Multiplicity = 1 (One)
    - Left End Navigation Property = Company
    - Right End Entity Dropdown = Company
    - Right End Multiplicity = * (Many)
    - Right End Navigation Property = Address
    5) Change the Association Name to: FK_Company_CompanyAddress
    6) Select the Left End Entity in the dropdown to be Company
    - The Association Name = CompanyCompany now
    7) Rename the Association Name to: FK_Company_CompanyAddress
    8) Select the Right End Entity in the dropdown to be CompanyAddress
    - The Association Name = CompanyCompanyAddress now
    9) Rename the Association Name again to: FK_Company_CompanyAddress
    10) Rename Right End Navigation Property to CompanyAddresses (from CompanyAddress)
    11) Choose OK.
    12) Under mapping details, choose CompaniesAddressesJoin as the "Maps to" table.

    These are the steps to create the association I am trying to create. Obviously, you could skip the first two entity name changes, and only change it once at the end. Thats what I do now, but I have to force myself to skip past the entity name and choose the ends first. From a usability standpoint, users tend to input data in the order they encounter it in a dialog, so since the Name comes first, I habitually type in the name I want then move on and select the ends. The name should remain customized if it is entered before selecting the ends. After creating this association and validating, I get the following error:

    Error 3034: Problem in Mapping Fragments starting at lines 263, 306: Two entities with possibly different keys are mapped to the same row. Ensure these two mapping fragments map both ends of the AssociationSet to the corresponding columns.

    This error is quite frustrating, because its WARNING you of a POSSIBLE issue...yet, the model still can't be used even if you have set up everything properly. All mappings map to the right keys in the right places at all times, there is no discrepancy. :'-(


    Here is more information so you can recreate a simple database and try it:

    TABLES
    ================================

    Addresses
    ----------------------------------------------------------------
    AddressID, int, not null, PK, IDENTITY
    StreetLine1, varchar(100), not null
    StreetLine2, varchar(100), not null
    City, varchar(50), not null
    State, char(2), not null
    Country, char(2), not null
    Zip, varchar(10), not null


    Companies
    ----------------------------------------------------------------
    CompanyID, int, not null, PK, IDENTITY
    Name, varchar(100), not null


    CompaniesAddressesJoin
    ----------------------------------------------------------------
    CompanyID, int, not null, PK, FK (to Companies.CompanyID)
    AddressID, int, not null, PK, FK (to Addresses.AddressID)
    IsPrimary, bit, false, not null


    CompanyAddress [View]
    ----------------------------------------------------------------
    CompanyID
    AddressID
    IsPrimary
    StreetLine1
    StreetLine2
    City
    State
    Country
    Zip

    From this simple schema, the ultimate goal is to have the following entity model. This entity model is simple, should require no heroics, and should be projectable if not for the requirement that entities built from table fragments all have the same exact key (I've never encountered a database where all related tables have the exact same key...there is usually a primary key, and one or more foreign keys that relate to other tables. Many times, all foreign key relationships are 1-1, allowing views to be used to merge the rows from those tables into a single logical "entity".) For example, CompaniesAddressesJoin and Addresses should easily be able to be merged, because it is a 1-1 relationship on the AddressID side...and 1-* only on the CompanyID side (and were not merging the CompanyID with anything). Basically, instead of the *-* relationship that is achieved by default when generating a model, I want to have a 1-* relationship between Companies and its addresses with payload...which is how it should be from a domain perspective.

    ENTITIES
    ================================

    Company
    ----------------------------------------------------------------
    CompanyID, Int32
    Name, String
    CompanyAddresses, Collection


    CompanyAddress
    ----------------------------------------------------------------
    AddressID, Int32
    StreetLine1, String
    StreetLine2, String
    City, String
    State, String
    Country, String
    Zip, String
    IsPrimary, Bool
    Company, Reference

    In my domain, I don't want a CompanyAddressJoin entity...at all..its simply a database level utility structure. Addresses in the database are normalized simply to keep from replicating the same data dozens of times. From a domain perspective, I want to have multiple address types, tuned to each parent they are collected under, that persist to an efficient data store. I don't really care that my database has addresses off in a separate location...my domain should not have to be dictated by my database model. So long as I can merge two tables together and consistently have single rows returned from each match in the merger (i.e. AddressID == AddressID will always return a single row...as if I was INNER JOINing rows into a view....I don't see why there is a conceptual difference between a view and an entity so long as the merger always produces single rows and not 1-*), I should be able to build the domain model I need. (If the restriction that all tables used in an entity have the same exact key is in place to ensure automatic CUD operations succeed, thats fine. However, if the CUD operations are overridden and custom stored procs used, the restrictions imposed for automatic CUD operations should be eliminated...they are not neccesary because I am explicitly taking care of them in the proper way for my data model).

    If you want a bigger picture. I could have a model like so:

    Company.CompanyAddressJoin[].Address
    Location.Address
    Warehouse.Address
    Contact.ContactAddressJoin[].Address

    This model would directly match the database, one entity per table in the database, which is usable, but not what we need or want. That forces us to become data driven in our domain model, and that sucks. My domain model should be driven by domain needs, not restricted in form by database needs. On top of that, the tables CompaniesAddressesJoin and ContactsAddressesJoin in the database have payloads, but in EDM, an association hides any additional contents of those join tables. I can't access the IsPrimary flags, or in the case of a Contact, an additional address type code. In my ideal model, we would have something like the following:

    Company.CompanyAddress[]
    Location.Address
    Warehouse.Address
    Contact.ContactAddress[]

    Unlike an Address, which is just address information, CompanyAddress has the additional IsPrimary property. ContactAddress has additional IsPrimary and AddressType properties. This seems like a simple, logical concept for a domain model to me. The whole idea behind Domain Driven Design is that you create the "entities" you need from a domain and business-need perspective, and project those entities onto a storage model when persisting (or the reverse when loading). The storage model has different structural needs to provide efficient storage and good performance, and thats the whole point of an O/R mapper...to bridge that gap, that impedance missmatch, allowing your domain to be independant of your data model...or at least not be explicitly dictated by it.

    I hate to say it, but in its current form, I don't think EF achieves this critical role. It accomplishes pretty much the same thing L2S did, with support for a small amount of additional but less common scenarios. It improves a little bit in the area of disconnected use of entities, and with the new WCF hints, improves graph serialization accross the wire. But in the area that everyone (regardless of whether they need POCO or not) needs support for, solving that impedance missmatch, EF doesn't provide the flexibility neccesary to be useful in most enterprise, n-tier applications. Until now, I thought that the "Vote of no Confidence" in EF was just a ploy by nHibernate and LLBLGEN fans to delay EF and give themselves a chance to compete. My opinion has changed however, and I do think that there are some fundamental, foundational issues with EF from an O/R mapping perspective that make it impractical for use beyond the basic, data-driven model scenario.

    Unless I am terribly mistaken and EF is not aiming to fill the role of an O/R mapper? (Its entirely possible that I have missed the goals behind EF.)
    Thursday, August 21, 2008 5:52 PM
  • I have managed to get a working model with my CompanyAddress entity. The model still contains the CompanyAddressJoin and Address entities, and although I would preferr it not, I can query the ObjectSpace and it materializes hierarchies as I need them. I had to build the model from scratch in XML to get everything working, using a DefiningQuery for the CompanyAddress entity, along with specifying only the AddressID as the entity key.

     

    I have run into another problem now, however. I am trying to model the AddressType lookup table (in my sample, my CompanyAddress has an AddressType, as I do not have the Contact entity like my full production schema does). The model is able to properly associate between CompanyAddressJoin and AddressType, however it can't associate between CompanyAddress and AddressType. The CompanyAddress entity is read-only, and has function mappings for CUD operations to ensure proper database integrity is maintained (CompanyAddress_Insert and CompanyAddress_Update call Address_Insert_Unique to insure that only unique instances of addresses are ever inserted into the Addresses table, and they also update the CompaniesAddressesJoin table to flip any entries previously marked IsPrimary to 0 if the inserted/updated row is marked IsPrimary. CompanyAddress_Delete only deletes the join record...leaving the Address record in tact).

     

    When I add an association between CompanyAddress and AddressType, I get the following error:

     

    Error 2048: The EntitySet 'CompanyAddresses' includes function mappings for AssociationSet 'CompanyAddressAddressType', but none exists in element 'DeleteFunction' for type 'EDMTestModel.CompanyAddress'. AssociationSets must be consistently mapped for all operations.

    I am not sure exactly what this error is referring to. The CompanyAddress_Delete proc only takes AddressID and CompanyID as parameters...it shouldn't require anything related to AddressType. Is there some specific reason why this error is appearing?

     

     

    Tuesday, August 26, 2008 5:49 AM
  • v1 of the EF has a number of restrictions on stored procedures which we are working to fix. One of them is that you must map all three sproc operations, not just one. Another is that all three sprocs must map the keys for the associations between the type and other types (where the association would be co-located), so that the system can also delete those associations. For example, If I have a Type A with key Id, and foreign key f that is surfaced as an association, then the delete sproc must take both Id as and f as parameters.

     

     

    Tuesday, August 26, 2008 3:06 PM
    Moderator
  • Adding the extra parameter to the delete function worked. Its not being used in any way, since we don't want to delete anything from the lookup table, but it works. Thanks.
    Wednesday, August 27, 2008 4:27 PM
  •  jrista wrote:

    Well, I renambed a bunch of entities, and suddenly noticed that whenever I change an entity from singular to plural, the designer, in that OH SO SO VERY VERY ANNOYING MICROSOFT FASION, decided to change the set name too!!

     

    Hi jrista -

     

    Sincere apologies for the annoying behavior -  it certainly was never our intent to annoy.  Quite to the contrary, we made the decision to change the entity set names in response to early feedback that not renaming entity sets was annoying.  It turns out that users were pretty confused when entity names and entity set names got out of sync.   Consider a model with an entity named "Food" and a corresponding entity set named "Foods".  Now consider what happens when the "Food" entity is reanmed to "Item".  If we didn't rename the entity set, then the newly renamed "Item" entity would be contained in entity set "Foods".  This is clearly non-sensical naming.   Users who were unaware of the additional step to manually rename the entity set ended up pretty confused when trying to program against the (mis-named) model.    Our decision was an attempt to avoid this confusion.

     

    As was previously mentioned, we're looking at some smarter pluralization & naming logic for the next version, including the ability to turn off our "smarts".

     

    Your feedback is really appreciated.  We'll definitely keep it in mind going forward. 

     

    Thanks,

     

    Mike Kaufman

    Microsoft Corp.  

    Tuesday, September 02, 2008 4:55 PM
    Moderator
  • I look forward to seeing what improvements are made. Obviously there are differences in the way people work...some want things done for them, others, like me, preferr to do things on their own. I was pretty frustrated when I originally created this thread, as I had spent hours tweaking a model only to find that the tool had changed things unexpectedly, and I had to go back and tweak it all over again. I think I was pretty harsh in my original post, and I apologize for that.

    Ultimately, what it boils down to, is UI usability. I guess its not something thats really primarily considered when writing a development IDE, but as Visual Studio becomes more and more complex, offering more and more capabilities, I think that improving usability needs to become a standard aspect of development. Something I have noticed over the last couple months working with and reading about EF is that there is a very wide array of methodologies, usage scenarios, and perspectives on use. There isn't any single development methodology for writing software, rather there are several very good methodologies in use today (TDD, DDD, SOA, etc.) Some methodologies advocate minimizing the amount of code manually written, some advocate writing all the code manually. Some methodologies advocate complete isolation of the business layer from the storage layer (POCO, PI), some don't make it an issue. Sometimes needs dictate a greater separation, sometimes they dictate a tighter coupling (say, for performance reasons event-based change tracking is often better.) Since Microsoft is in the business of developing core frameworks upon which many thousands of applications are built, its important that the variety of these development methodologies are supported...but not just from a pure code standpoint. Making sure the tools support the various usage scenarios is pretty important too, especially given the complexity of object-relational mapping.

    A few suggestions for improving the UI to make it more flexible for the variety of usage scenarios, and to just make it more stable during updates regardless of the usage scenario:

    1) Allow a much greater degree of control over the code generation.
    a) Allow existing CSDL, SSDL, and MSL items to be ignored during generation on a per-table/view/proc basis. (Simple, and if we could have it in the short term, it would save a HUGE amount of time spent remodifying xml after each update from the database).
    b) Allow developers to choose their naming/plurality scheme and have it saved somewhere so its keept between updates.
    c) Don't overwrite something that has been manually modified (i.e. if an EnitySet is manually named, keep it, regardless of what the Entity name is changed to).
    2) Support the full set of EDM capabilities in the visual designer.
    a) All three common table mapping types (TPT, TPH, TPC) should be supported at the least.
    b) EDM supports a more flexible approach to mapping beyond the three standard types...if possible, these more flexible mapping scenarios should be supported in the visual designer.
    c) Support all attributes that can be used in xml in the designer...like StoreGeneratedPattern.
    3) Support modification of the SSDL in the visual designer.
    a) Views generate poorly, automatically using all non-nullable properties as the entity key. This is RARELY desired, but the only way to fix it is by manually editing the xml.
    b) Don't override table keys that have been manually fixed during an update, or provide some way of locking the key on a per-table/view basis.
    4) Don't always require that relationships that exist in the database physically exist in the conceptual model.
    a) If an FK exists between two entities in the database, allow the developer to choose whether or not to include it in the model. (I've reverted to adding tables a couple at a time to my model, rather than all at once, to prevent unwanted artifacts like foreign keys to be added to the SSDL, which during an update, are always added back to my conceptual schema even when they cause problems are are just unwanted...the value of having FK's as associations in the SSDL, which then must also be in the CSDL and mapped between the two...eludes me...I've been able to create models manually that do not have any underlying FK's in the SSDL to match the associations from my CSDL).
    5) Support store-generated column values/defaults better in the visual designer.
    a) If a column is generated by the database, either IDENTITY, or has a calculated/computed default value (i.e. a Date column with GetDate() as the default), support it during generation and updates (the table IDENTITY column is supported...but no other generated values, particularly non-scalar defaults, are).
    b) Allow the StoreGeneratedPattern value to be edited in the visual designer, so that even if the generation pattern can not be automatically detected, it can at least be set without having to go to the xml.
    c) Do not remove the StoreGeneratedPattern value when updating...unless you can detect that its not required (i.e. the GetDate() default was removed from the Date column in the database...so remove it from the model).
    6) Offer better validation messages, and automatically recover from problems in the designer layout xml.
    a) Sometimes, the designer layout content in a .edmx file stops working...causing a vauge error message to appear when opening the visual designer. The only solution is to delete the designer section...which then causes the model to rearrange every time it is opened visually. The cause is unknown...seems to happen randomly. An exception from a botched designer layout section should be trapped internally and the layout redone without errors.
    b) Quite often, after making updates either manually (more frequently) or sometimes with the designer (less frequently), the next save will cause a vauge error (usually index not found) to occurr at line 1, column 1 of the .edmx file. The only solution is to undo previous edits (if they can be remembered) one by one until the model works again...or, in the event that you can not find the problem, recreate the model from scratch. If the error is due to invalid XML, a better error stating the xml line number the error occurs on should be displayed. If the error is due to some problem with the EDM definition itself, then a more accurate error should be displayed indicating where the problem is in the model (line 1, column 1 is about as vauge as it gets).

    Overall, EDM seems to support a decent variety of mapping scenarios. It has some limitations that make building the desired conceptual model from an existing, populated schema difficult (i.e. requiring that all tables involved in entity splitting have the same columns for the key in every table), but over time I think (hope) that many of those limitations will go away. The greatest difficulty with using entity framework right now lies in the fact that the visual designer does not support the full range of capabilities offered by EDM. Developers either have the option of limiting themselves and conforming to what the visual designer supports (maybe possible with a brand new project...less likely given an existing project that has established business objects and needs an O/RM), ditching the visual designer and manually managing all updates to the EDM files (which a lot of times is just not practical given the tens of thousands of lines that .edmx or .csdl, .ssdl, and .msl files may contain for an average database), or taking the frustrating route of using the visual designer, and repeatedly redoing manual edits after each update. I think I've said this before, but ultimately, regardless of the need for POCO, PI, snapshot-based change tracking, n-tier support, and all that...what we all need is an O/R Mapper...something that will automatically bridge that gap between how we use objects, and how we store data...and design tools that support the mappings we need to make.

    Well, I'm sure you guys have had enough of my ramblings. I look forward to hearing more about what is planned for EF v2...I'm eager to start using EF in a practical way, but it might have to wait for the next version (at least for existing applications/databases).
    Tuesday, September 02, 2008 7:25 PM
  • I read your last post end to end and I absolutely agree with you. The designer in its current state is very bad. I've spent alot of energy and time acting troubleshooting this tool and I think that it's the key to EDM adoption. The only thing I'd add to your list is the ability to break down edmx files into domains so that we can don't need to look at this huge model at once. This is very important to alot of customers. I think that the PMs should pay attention and focus alot of their resources on the designer & POCO support, then move on to other ideas. With a tool this important, you can't do it half *** and keep moving on or you'll end up with garbage in the end. My 2 cents.

     

    Travis

     

    Wednesday, September 10, 2008 4:16 PM
  • I agree about breaking down EDMX files. I tried to post this to an RFC thread started by Noam yesterday, but for some reason the post never went through. So here it is again:

     

    Another of the drawbacks of EDMX files right now is that the visual designer can only handle a very limited amount of entities before it becomes too cluttered to manage, or simply too populated to function (hundreds to thousands of entities just bring VS to a crawl). I would like to propose something along the lines of entity "views" in the EDMX design surface. This would allow developers to manage a very large conceptual model, without having to have every entity visible at all times. Views should have a name, and subsets of the entire set of entities should be able to be dropped on each view. There might be a couple tricky things to work out, such as how to deal with changes in an entity that affect references to "off-view" entities, how to handle entity deletes when they may be referenced by "off-view" entities, etc. Warnings or error messages might be sufficient to handle those situations, or maybe a more elegant solution can be discovered.

     

    Not only will this help with large models, but it could help to partition models backed by a single store into more logical business/department oriented subsets where there is no crossover (or associations between entities in different views). Maybe it's also possible to support multi-file EDMX, where the SSDL is stored in a central location, and the various partitions (each with their own set of views) store their CSDL/MSL in individual files.

     

    Of course, this all naturally leads into the question partitioning generated code as well. Currently, in a moderately large model, the generated code file can be immense. Tens of thousands of lines, if not more. In addition to being able to set up views for a design surface, and possibly partition EDMX files into multiple, isolated models, more control over code generation is needed as well. It would be nice of the code generator could be configured to generate files per-partition at the least, and even better per-class (one for the context, one for each entity). I am not sure how possible such generation is, given that all existing code generation file types in VS only ever have one generated file. Perhapse partitioning EDMX into multiple files is the only option, but at least that would allow really huge models to be managed in a better, more performant manner with smaller files.

    Wednesday, September 10, 2008 4:32 PM