Domain Model class generates no key

12 posts, 0 answers
  1. Stefan Lorenz
    Stefan Lorenz avatar
    13 posts
    Member since:
    May 2010

    Posted 29 Jul 2010 Link to this post

    Hi,

    I've designed a simple class MyData with a field "MyData_id" (INT32, Identity=True). Whether I select "Default" or "HighLow" as Identity Mechanism, if I create a new instance, it's MyData_id is 0. On calling SaveChanges()  I get an DataStore-Exception (Insert of '1449231688-12' failed due to IDENTITY INSERT=OFF).

    I used OA's HighLow-generator before with classic forward mapping and it ran out of the box, without messing around with identity insert. It should show the same behaviour using the domain model, right?

    Thanks in advance
    Stefan
  2. PetarP
    Admin
    PetarP avatar
    754 posts

    Posted 02 Aug 2010 Link to this post

    Hi Stefan Lorenz,

     We tried to reproduce your problem but without luck. Is it possible for you to open a support ticked and send us a small project that recreates the problem you have encountered? This will greatly help us in solving the issue. 
    We are looking forward to your reply.

    Regards,
    Petar
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  3. DevCraft banner
  4. Daniel Plomp
    Daniel Plomp avatar
    130 posts
    Member since:
    Feb 2004

    Posted 11 Aug 2010 Link to this post

    Hi,

    I experience the same problem. With the classic way of ORM, after I did a commit, I could get the ID of my new inserted record.
    Now I use the Domain Model and then after the SaveChanges() it won't work?

    Here's the code of my function:

    public int SaveOffer(int offerid, string username, int materialid, int materialcompletionid, int washupid, int washupcraneholes,
                int hotplatesavingid, int kitchensetupid, int worktopbordertypeid) 
            {
                Offer offer = null;
      
                using (SinedModelContext db = new SinedModelContext())
                {
                    if (offerid != 0)
                    {
                        // Update an existing offer
                        offer = this.GetOffer(offerid);
                        offer.DatetimeChanged = DateTime.Now;
                    }
                    else
                    {
                        // Create a new offer
                        offer = new Offer();
                        offer.DatetimeCreated = DateTime.Now;
                        offer.DatetimeChanged = DateTime.Now;
                    }
      
                    offer.Username = username;
                    offer.MaterialId = materialid;
                    offer.MaterialCompletionId = materialcompletionid;
                    offer.WashupId = washupid;
                    offer.WashupCraneHoles = washupcraneholes;
                    offer.HotPlateSavingId = hotplatesavingid;
                    offer.KitchenSetupId = kitchensetupid;
                    offer.WorkTopBorderTypeId = worktopbordertypeid;
      
                    db.SaveChanges();
                      
                }
      
                // Return the offerid (is 0, instead of the new value???)
                return offer.OfferId;
            }
  5. Damyan Bogoev
    Admin
    Damyan Bogoev avatar
    581 posts

    Posted 12 Aug 2010 Link to this post

    Hi Daniel,


    You should slightly modify your code in order to make it work correctly:
    1. Firstly, when you try to insert an object to the database you should use the OpenAccessContext.Add method. This method will mark the object for insertion and if the transaction is committed it will be inserted. The transaction is committed when the OpenAccessContext.SaveChanges method is called.
    2. You should use one and the same OpenAccessContext instance for retrieving and editing an object. The OpenAccessContext manages the object’s state. If you try to use one context for retrieving the object and later another for persisting the changes to the database the changes will not be saved.
    Now the code should look like this:

    public int SaveOffer(int offerid, string username, int materialid, int materialcompletionid, int washupid, int washupcraneholes,
                int hotplatesavingid, int kitchensetupid, int worktopbordertypeid)
    {
        Offer offer = null;
     
        using (SinedModelContext db = new SinedModelContext())
        {
            if (offerid != 0)
            {
                // Update an existing offer
                offer = this.GetOffer(offerid, db); // point #2
                offer.DatetimeChanged = DateTime.Now;
            }
            else
            {
                // Create a new offer
                offer = new Offer();
                offer.DatetimeCreated = DateTime.Now;
                offer.DatetimeChanged = DateTime.Now;
                 
                db.Add(offer); // point #1
            }
     
            offer.Username = username;
            offer.MaterialId = materialid;
            offer.MaterialCompletionId = materialcompletionid;
            offer.WashupId = washupid;
            offer.WashupCraneHoles = washupcraneholes;
            offer.HotPlateSavingId = hotplatesavingid;
            offer.KitchenSetupId = kitchensetupid;
            offer.WorkTopBorderTypeId = worktopbordertypeid;
     
            db.SaveChanges();
               
        }
     
        // Return the offerid (is 0, instead of the new value???)
        return offer.OfferId;
    }
     
    // point #2
    public Offer GetOffer(int offerId, SinedModelContext db)
    {
        return db.Offers.FirstOrDefault(o => o.OfferId == offerId);
    }

    You could find this help article useful, it demonstrates how to perform CRUD operations with Telerik OpenAccess ORM.
    Hope you will find helpful the provided information. If any other questions arise please contact us back.


    Kind regards,
    Damyan Bogoev
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  6. Daniel Plomp
    Daniel Plomp avatar
    130 posts
    Member since:
    Feb 2004

    Posted 12 Aug 2010 Link to this post

    Hi Damyan,

    Thanks for the reply. I understand what I forgot.
    What would be the best practice for webapplications?

    I used to work with the ScopeFactory solution and that worked well within my solution (DAL, BLL and UI).
    I thought that with this new approach it would work out of the box (a little naive maybe :) )

    For example: I use different repositories that are inside a seperate project. Also, I pass through objects to other functions, but then I also get the message about different scopes.
    Is there already a solution for this?

    Thanks,
    Daniel
  7. Damyan Bogoev
    Admin
    Damyan Bogoev avatar
    581 posts

    Posted 13 Aug 2010 Link to this post

    Hi Daniel,

    1. You could find the following KB articles useful as they explain the best practices for dealing with the OpenAccessContext in a web application:
    Another useful resource is this code library example “Implementing Context factory for Telerik OpenAccess ORM”.
    2. You should always use the OpenAccessContext.Add method when you try to insert new object to the database otherwise Telerik OpenAccess ORM will not persist or track this entity for changes.
    3. The only solution is to work with one and the same OpenAccessContext instance for retrieving and modifying an entity as I explained in point #2 from my previous post.

    Hope you will find the provided information useful. If any other questions arise please do not hesitate to contact us back.


    Sincerely yours,
    Damyan Bogoev
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  8. Daniel Plomp
    Daniel Plomp avatar
    130 posts
    Member since:
    Feb 2004

    Posted 18 Aug 2010 Link to this post

    Hello Damyan,

    Thanks for the reply.
    I used the approach in Best Practices in web development with OpenAccess - Part Two

    I have created the 'ContextFactory' class inside my Repository project and created a constructor inside each repository class that sets the current HttpContext.

    public class ArticleRepository
    {
       protected DataModelContext context;
         
       public ArticleRepository(HttpContext current)
       {
           context = ContextFactory.GetContextPerRequest(current);
       }
         
       public Article GetArticle(int articleid)
       {
          try
          {
             return context.Articles.Where(x => x.ArticleId == articleid).FirstOrDefault();
          }
          catch (Exception ex)
          {
             throw ex;
          }
       }
    }


    Now should'nt I do anything to dispose the items inside the Context object?

    If I would do everything within a web project, I would use this approach:

    using (DataContext c = new DataContext)
    {
       ...
    }

    And I read that with this approach disposal is taking care of...

    So, is my solution save?

    Regards,
    Daniel
  9. Damyan Bogoev
    Admin
    Damyan Bogoev avatar
    581 posts

    Posted 18 Aug 2010 Link to this post

    Hi Daniel,

    Yes, it is recommended to dispose the OpenAccessContext instance from the code behind. A good approach is to dispose the context within the Page_Unload method:
    protected void Page_Unload(object sender, System.EventArgs e)
    {
        ...
        if(context != null)
        {
            context.Dispose();
        }
    }


    Best wishes,
    Damyan Bogoev
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  10. Daniel Plomp
    Daniel Plomp avatar
    130 posts
    Member since:
    Feb 2004

    Posted 18 Aug 2010 Link to this post

    Hi Damyan,

    I'm not setting the context inside my page or masterpage, but in a seperate project. (as you can read in my previous post).
    How should I convert the ScopeFactory method that was provided by telerik, to use it for the new context approach?

    So in my webapplication I do this to make use of my repository:

    private void BindGrid()
    {
       try
       {
          OfferRepository rep = new OfferRepository();
          this.gridKitchenSetups.DataSource = rep.GetKitchenSetups();
          this.gridKitchenSetups.DataBind();
       }
       catch (Exception ex)
       {
          throw ex;
       }
    }

    Regards,
    Daniel
  11. Damyan Bogoev
    Admin
    Damyan Bogoev avatar
    581 posts

    Posted 19 Aug 2010 Link to this post

    Hello Daniel,

    1. Here is the implementation of the ScopeFactory method which uses an OpenAccessContext object:

    public class ContextFactory
    {
        public static YourContextName GetContextPerRequest(HttpContext httpContext)
        {
            if (httpContext == null)
            {
                return new YourContextName();
            }
            else
            {
                string key = httpContext.GetHashCode().ToString("x") + System.Threading.Thread.CurrentContext.ContextID.ToString();
                YourContextName context = null;
                if (httpContext == null)
                {
                    context = new YourContextName();
                }
                else
                {
                    context = (YourContextName)httpContext.Items[key];
                    if (context == null)
                    {
                        context = new YourContextName();
                        httpContext.Items[key] = context;
                    }
                }
                return context;
            }
        }
    }

    2. At first, I am sorry for the incorrect answer in my previous post.  I recommend you using the following approach in order to be able to dispose the OpenAccessContext instance from the web application:
    - Implement the IDisposable interface within the repository class;
    - Dispose the OpenAccessContext instance in the IDisposable.Dispose() method:

    public class RepositoryClass : IDisposable
    {
        ...
        public void Dispose()
        {
            this.context.Dispose();
        }
    }

    - Now you could use a repository instance in the following way:

    using(RepositoryClass repository = new RepositoryClass())
    {
       ...
    }

    Hope that helps.


    All the best,
    Damyan Bogoev
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  12. gmendez
    gmendez avatar
    82 posts
    Member since:
    Jun 2012

    Posted 09 Jun 2011 Link to this post

    Hello, I'm also have the same problem. I think I'm doing things as suggested. Even this is a very simple scenario I can't figure out what's wrong.
    I have 2 classes: Persona and Telefono (Person and Phone). A person can have one or many phones.
    In both classes at the model designer I assigned Id properties of type int32 and set them to IsIdentity=true.
    The first question is: Where is the key generator specified? I didn't find an option for that at the properties grid for the Id property.
    The second question relates to the first in the sense that the first object I create has it's id set to 0, and so does all subsequent objects, thus, getting an exception after the first one was inserted. The first Telefono object has it's Id set to 0 too.
    The third question is: No "voa_keygen" table was created. Is this Ok?
    I'm new to the model approach, so any help will be very appreciated.

    The code I'm testing is the following:
    private void btnCreate_Click(object sender, EventArgs e)
    {
        EntitiesModel context = new EntitiesModel();
        Persona p = new Persona();
        p.Nombre = "Person Name";
        p.FechaIngreso = DateTime.Today;
        p.Notas = "Some notes";
        p.Telefonos.Add(new Telefono() { Numero = "12345", Descripcion = "Home", Persona = p });
        context.Add(p);
        context.SaveChanges();
    }

    Thanks in advance,

    Gonzalo
  13. gmendez
    gmendez avatar
    82 posts
    Member since:
    Jun 2012

    Posted 09 Jun 2011 Link to this post

    Ok, found it.
    I didn't realize I must set the generator type at the class level, not the property :)
Back to Top
DevCraft banner