This is a migrated thread and some comments may be shown as answers.

Domain Model class generates no key

11 Answers 126 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Stefan Lorenz
Top achievements
Rank 1
Stefan Lorenz asked on 29 Jul 2010, 09:22 AM
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

11 Answers, 1 is accepted

Sort by
0
PetarP
Telerik team
answered on 02 Aug 2010, 12:38 PM
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
0
Daniel Plomp
Top achievements
Rank 2
answered on 11 Aug 2010, 09:30 PM
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;
        }
0
Damyan Bogoev
Telerik team
answered on 12 Aug 2010, 04:33 PM
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
0
Daniel Plomp
Top achievements
Rank 2
answered on 12 Aug 2010, 08:38 PM
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
0
Damyan Bogoev
Telerik team
answered on 13 Aug 2010, 03:46 PM
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
0
Daniel Plomp
Top achievements
Rank 2
answered on 18 Aug 2010, 01:37 PM
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
0
Damyan Bogoev
Telerik team
answered on 18 Aug 2010, 04:46 PM
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
0
Daniel Plomp
Top achievements
Rank 2
answered on 18 Aug 2010, 04:53 PM
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
0
Damyan Bogoev
Telerik team
answered on 19 Aug 2010, 05:03 PM
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
0
gmendez
Top achievements
Rank 1
answered on 09 Jun 2011, 06:06 PM
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
0
gmendez
Top achievements
Rank 1
answered on 09 Jun 2011, 09:01 PM
Ok, found it.
I didn't realize I must set the generator type at the class level, not the property :)
Tags
General Discussions
Asked by
Stefan Lorenz
Top achievements
Rank 1
Answers by
PetarP
Telerik team
Daniel Plomp
Top achievements
Rank 2
Damyan Bogoev
Telerik team
gmendez
Top achievements
Rank 1
Share this question
or