Ryan Cox
Ryan Cox

Reputation: 958

Two objects of the same class, one is overwritten

I have two objects of type ProductInformation, which contains properties for productId, productName, and price. I also have a method that queries a database for this information to populate the product class.

ProductInformation giftcard = query.ExecuteQuery(10) //this returns a giftcard
ProductInformation giftCertificate = query.ExecuteQuery(9) //this returns a gift certificate

I have stepped through the queries, and can confirm that, after running the first line, the gift card is successfully populated. However, somehow, after I create the gift certificate, it overwrites the gift card object with the properties from the gift certificate. To my understanding, they should be seperate objects. What am I missing so that I can keep the gift card?

For reference, the queries I'm using are essentially

SELECT *
FROM Products
WHERE ProductName like '%gift card'

And

SELECT *
FROM Products
WHERE ProductName like '%gift certificate'

The only thing I can think of is that my query class has a private ProductInformation object that I'm using to return to the giftcard and giftcertificate like

ProductInformation thisProduct;
public ProductInformation ExecuteQuery(int i)
{
    switch (i)
        case 10:
            thisProduct = GiftCard();
            break;
        case 9:
            thisProduct = GiftCertificate();
            break;
    return thisProduct;
 }

private ProductInformation GiftCard()
{
    using (SqlConnection con = new SqlConnection(conectionString))
    {
        con.Open();
        return con.query<ProductInformation>(giftCardQuery).First();
    }
}
private ProductInformation GiftCertificate()
{
    using (SqlConnection con = new SqlConnection(connectionString))
    {
        con.Open();
        return con.query<ProductInformation>(giftCertQuery).First();
    }
}

but since I'm assigning thisProduct to local variables in my test method, that should create new instances of the class, right?

Upvotes: 0

Views: 996

Answers (5)

S2S2
S2S2

Reputation: 8502

To expand on other answers, ProductInformation is a reference type and reference types are always passed By Reference. Moreover, if you declare it at class level, same instance will be returned by both the calls, further to that the calling code receives the same instance of ProductInformation object as its declared at class level and same query object is used in both the method calls.

So, idea to use separate instances of ProductInformation object would be achieved if you move that variable to inside those methods, so it will be destroyed when the method call exits and recreated when next method call starts.

More info on memory management, refernce and value types is on Eric Lippert's blog:

Upvotes: 0

Gregory A Beamer
Gregory A Beamer

Reputation: 17010

Part of the problem here is the use of LINQ. The execution is deferred until use. What this means is the object may not be changing, per se, it just may have never been set until you query it.

Regardless, the pattern you are using is rather strange. Why didn't you opt for a more repository focused data access methodology. It is much cleaner than funneling everything through a quasi-singleton to get data. It is also a better separation of concerns.

@TMKeown has an interesting solution that will likely solve the immediate concern, but as an architect, I would be more concerned with the way you have set to solve the problem. Why are you funneling things through in this manner. If there is a good motivation, there should be a pattern that keeps the motivation without carrying forward the problems associated (one object magically becomes another).

Upvotes: 0

OttO
OttO

Reputation: 419

Both giftcard and giftCertificate the same instance and the second statement just changes the existing object. I guess putting

thisProduct = new ProductInformation();

before switch statement in ExecuteQuery method should help. Also it look like that the thisProduct shouldn't be on class level scoped.

ProductInformation thisProduct;

public ProductInformation ExecuteQuery(int i)
{
    thisProduct = new ProductInformation();
    switch (i)
        case 10:
            thisProduct = GiftCard();
            break;
        case 9:
            thisProduct = GiftCertificate();
            break;
    return thisProduct;
 }

Upvotes: 1

Guffa
Guffa

Reputation: 700382

"since I'm assigning thisProduct to local variables in my test method, that should create new instances of the class, right?"

No, assigning a reference doesn't automatically create a new instance.

If you use the same object for reading from the database, and then assign that object to a variable in the hope that it will create a separate instance, then that is the problem. You will just end up with two references to the same object, so when you read data for the next object into it, it will overwrite the previous data.

You should create a new instance for each object that you want to read.

Upvotes: 3

T McKeown
T McKeown

Reputation: 12857

Doesn't look like a local variable:

ProductInformation thisProduct;

ExecuteQuery(int i)
{
   switch (i)
      case 10:
          thisProduct = GiftCard();
          break;
       case 9:
          thisProduct = GiftCertificate();
          break;
    return thisProduct;
 }

Your Query class is being used to load both, and the query object is referencing the same ProductInformation instance. You have 2 options in my opinion:

-Use 2 query instances, because your query class has state (bad idea).

-Move your ProductInformation thisProduct variable inside the ExecuteQuery() method.

Upvotes: 2

Related Questions